Lời cám ơn
Mạng internet tốc độ cao ADSL xuất hiện ở Việt Nam chỉ vài năm gần đây nhưng ảnh hưởng của nó tới cuộc sống và lối sống của người Việt rất rõ ràng. Internet đã thành một thứ không thể thiếu với cộng đồng từ nhà nước tới người dân, từ người già tới giới trẻ. Internet mang tới một kênh thông tin truyền thông hiệu quả tới người sử dụng. Kéo theo sự phát triển đó là thương mại điện tử. Thương mại điện tử là một lĩnh vực mới đang được nhiều cơ quan, nhiều công ty, đoàn thể cũng như cá nhân nghiên cứu và phát triển nhằm đưa các thiết bị, các ứng dụng liên quan đến điện tử tin học vào phục vụ cho sự phát triển kinh doanh. Thương mại điện tử của Việt Nam phát triển đi kèm với sự phát triển của lượng khách hàng. Khách hàng của các trang thương mại điện tử của Việt Nam hiện nay phần lớn là giới trẻ, họ trao đổi, buôn bán với nhau các vật dụng công nghệ cao như điện thoại, máy vi tính, sách vở tạp chí thậm chí là quần áo, đồ dùng gia đình. Đó là lý do em thực hiện đồ án tốt nghiệp xây dựng website bán hàng trực tuyến này.
Trên cơ sở muốn tìm hiều về Web và ứng dụng của Web, cũng như những phát triển của nó, em thực hiện đề tài: “Nghiên cứu jsp & java – Xây Dựng Website bán Giấy Dán Tường”. Bước đầu nghiên cứu, hiện thực với kiến thức, khả năng và thời gian có hạn, đồ án này chắc chắn sẽ không tránh khỏi những thiếu sót, rất mong được thầy cô và các bạn góp ý để có thể hoàn chỉnh hơn trong quá trình nghiên cứu sau này.
Em xin chân thành cảm ơn sự giúp đỡ tận tình của các thầy có trong suốt quá trình thực tập và làm đồ án tốt nghiệp, đặc biệt là Ths. Phan Hữu Trung người đã trực tiếp hướng dẫn em trong toàn bộ quá trình thực hiện để hoàn thành đồ án tốt nghiệp này.
Phụ lục
Phần 1. Giới thiệu tổng quan. 3
1.1.Đặt vấn đề. 3
1.2.Công nghệ sử dụng. 4
1.3.Chức năng của website. 4
Phần 3. Phân tích và thiết kế. 6
3.1Chức năng của hệ thống. 6
3.1.1Khách ghé thăm website. 6
3.1.2Chức năng thành viên. 7
3.1.3Chức năng của admin. 7
3.2ERD8
3.3Thiết kế cơ sở dữ liệu. 10
3.3.1Bảng tin tức (news). 11
3.3.2Bảng comments. 11
3.3.3Bảng sản phẩm(products). 11
3.3.4Bảng nhà cung cấp(suppliers). 12
3.3.5Bảng nhóm sản phẩm(categories). 12
3.3.6Chi tiết hóa đơn(cart_detail). 13
3.3.7Hóa đơn(Cart). 13
3.3.8Người dùng(customer). 14
Phần 4. Thiết kế giao diện và cài đặt chương trình. 14
4.1Tổng quát về công nghệ và công cụ sử dụng. 14
4.1.1 Tổng quát về PHP. 14
4.1.2 Cú pháp của PHP. 18
4.1.3 Tổng quát về MySQL Server. 23
4.1.4 Tổng quát về Ajax. 24
4.2Framework symfony. 29
4.2.1 Giới thiệu. 29
4.2.2 Cài đặt symfony. 31
4.2.3Cài đặt Project33
4.2.4Tạo Application. 34
4.2.5Cài đặt Web server. 36
4.2.6Phát triển một dự án với symfony. 39
4.3Giao diện và các chức năng của chương trình. 61
4.2.1 Giao diện chính. 61
4.3.3Trang đăng ký thành viên. 62
4.3.4Đăng Nhập. 62
4.3.4.1 . Trang giỏ hang. 64
4.3.5Đặt Hàng. 64
4.3.6Thông kê những đơn hàng đã đặt65
4.3.7Hình ảnh một số mẫu giấy dán tường. 65
4.3.8Trang tin nội thất66
4.3.9Trang quản trị67
4.3.10Trang quản lý tin tức. 67
4.3.11Quản lý sản phẩm68
4.3.12Trang quản lý người dùng. 68
4.3.13Trang quản lý hóa đơn. 69
4.3.14Trang quản lý hình ảnh. 69
4.3.15Trang nhóm sản phẩm70
Phần 5. Kết luận. 70
5.1Những điều đã làm được :70
5.2Hạn chế:71
5.3Hướng phát triển :71
5.4 Tài liệu tham khảo. 71
73 trang |
Chia sẻ: lvcdongnoi | Lượt xem: 2879 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Xây Dựng Website bán Giấy Dán Tường, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
dẻo để thích nghi với những trường hợp phức tạp - Hoạt động theo cấu hình định trước -- lập trình viên chỉ cần cấu hình trong những trường hợp riêng biệt - Tuân theo những hoạt động và mẫu thiết kế tốt nhất - Sẵn sàng cho môi trường xí nghiệp -- thích nghi với những chính sách và kiến trúc công nghệ thông tin và đủ ổn định cho những dự án dài hạn. - Mã rất dễ đọc, với những chú thích kiểu phpDocumentor, dễ dàng bảo trì - Dễ dàng mở rộng, cho phép tích hợp với những thư viện khác Những tính năng dự án web được tự động. Hầu hết các chức năng thông thường của những dự án web được tự động trong symfony, như sau: - Lớp internationalization có sẵn cho phép phiên dịch giao diện, dữ liệu cũng như là content localization. - Phần presentation sử dụng template và layout có thể được xây dựng bởi người thiết kế HTML mà không cần có kiến thức về framework. Các helper làm giảm số lượng mã presentation phải viết bằng cách tóm gọn các phần của mã vào những function đơn giản. - Các form hỗ trợ kiểm tra và điền tự động, và điều này đảm bảo chất lượng tốt của dữ liệu trong cơ sở dữ liệu và kinh nghiệm người sử dụng tốt hơn. - Việc escape output bảo vệ các ứng dụng khỏi những tấn công thông qua dữ liệu bị hỏng. - Những tính năng quản lý cache giúp giảm lượng băng thông và tải của máy chủ. - Những tính năng phân quyền và xác nhận giúp việc tạo các quản lý những mục hạn chế và bảo mật người dùng dễ dàng hơn. - Việc định hướng và các URL thông minh làm cho phần địa chỉ của các trang trở nên thân thiện với máy tìm kiếm. - Các tính năng quản lý API và email sẵn có cho phép ứng dụng web vượt qua những tương tác trình duyệt cổ điển. - Các danh sách trở nên thân thiện với người dùng hơn nhờ việc phân trang, sắp xếp và tìm kiếm 1 cách tự động. - Các factory, plugins và mixins cung cấp khả năng mở rộng ở mức cao. - Các tương tác AJAX dễ hiện thực nhờ vào các helper 1 dòng tóm lượt những hiệu ứng javascript tương thích với các trình duyệt. Môi trường và công cụ phát triển: Để đáp ứng những yêu cầu của những doanh nghiệp có các chuẩn viết mã riêng và các qui tắc quản lý dự án, symfony có thể hoàn toàn được tùy biến. Mặc nhiên nó cung cấp một vài môi trường phát triển và được gói gọn với nhiều công cụ để tự động hóa những nhiệm vụ công nghệ phần mềm thông thường: - Các công cụ sinh mã tự động rất tuyệt cho việc tạo bản prototype và phần quản lý backend chỉ với vài dòng lệnh. - Unit và funtional testing framework sẵn có cung cấp những công cụ rất tốt cho phép test-driven developement - Debug: giúp debug tất cả thông tin mà lập trình viên cần trên trang - Giao diện chế độ dòng lệnh tự động hóa triển khai các ứng dụng giữa hai server - Tính năng logging cung cấp cho adminnistrators những chi tiết đầy đủ về sự hoạt động của một ứng dụng.
4.2.2 Cài đặt symfony
Đầu tiên, tạo một thư mục để chứa các file của project Jobeet:
c:\> mkdir c:\development\sfprojects\jobeet
c:\> cd c:\development\sfprojects\jobeet
Tạo thư mục để chứa thư viện symfony:
$ mkdir -p lib/vendor
Để cài đặt symfony, download file nén trên trang web symfony. Hướng dẫn này được viết trên symfony 1.2, hãy download phiên bản mới nhất của symfony 1.2.
Ở mục "Source Download", bạn sẽ tìm thấy file nén dạng .tgz hoặc .zip. Download file này và copy vào thư mục vừa tạo lib/vendor, sau đó giải nén:
$ cd lib/vendor
$ tar zxpf symfony-1.2-latest.tgz
$ mv symfony-1.2.0 symfony
Ở Windows, việc giải nén file zip có thể làm từ menu chuột phải. Sau khi đổi tên thư mục thành symfony, chúng ta có thư mục như sau c:\development\sfprojects\jobeet\lib\vendor\symfony.
Do cấu hình PHP có thể khác nhau, chúng ta cần kiểm tra lại cấu hình PHP để chắc chắn các yêu cầu tối thiểu để chạy symfony được đáp ứng. Chạy đoạn script kiểm tra từ dòng lệnh:
$ cd ../..
$ php lib/vendor/symfony/data/bin/check_configuration.php
Nếu có vấn đề, màn hình sẽ đưa ra gợi ý và cách sửa. Bạn có chạy file kiểm tra cấu hình PHP từ trình duyệt. Copy file vào thư mục gốc của web server và truy cập từ trình duyệt. Đừng quên xóa file đi sau khi đã kiểm tra xong.
Nếu đoạn script không hiện thông báo lỗi, hãy kiểm tra để chắc rằng symfony được cài thành công bằng cách sử dụng lệnh của symfony để xem phiên bản (chữ cái V viết hoa):
$ php lib/vendor/symfony/data/bin/symfony -V
Ở Windows:
c:\> cd ..\..
c:\> php lib\vendor\symfony\data\bin\symfony -V
Nếu bạn muốn xem tất cả các lệnh của symfony, gõ symfony để xem danh sách các lệnh:
$ php lib/vendor/symfony/data/bin/symfony
Ở Windows:
c:\> php lib\vendor\symfony\data\bin\symfony
Các lệnh của symfony rất hữu dụng. Nó cung cấp rất nhiều công cụ giúp cho việc phát triển sản phẩm của bạn tiện lợi như xoá cache, tự động sinh code, ...
Cài đặt Project
Trong symfony, các application có chung một cơ sở dữ liệu (data model) được nhóm lại trong một project. Với project Jobeet, chúng ta có 2 application: frontend và backend.
Từ thư mục jobeet, chạy lệnh generate:project để tạo 1 project symfony:
$ php lib/vendor/symfony/data/bin/symfony generate:project jobeet
Ở Windows:
c:\> php lib\vendor\symfony\data\bin\symfony generate:project jobeet
Lệnh generate:project tạo ra cấu trúc file và thư mục mặc định cần cho một project symfony:
Tại sao symfony tạo ra quá nhiều file vậy? Một trong những lợi ích của việc sử dụng full-stack framework là chuẩn hoá sự phát triển của bạn. Nhờ cấu trúc file và thư mục thống nhất của symfony, bất kì lập trình viên nào có hiểu biết về symfony cũng có thể thực hiện công việc bảo trì cho bất kì dự án symfony nào. Sau một thời gian ngắn, anh ta đã có thể bắt đầu code, sửa lỗi, và thêm tính năng mới.
Lệnh generate:project cũng tạo một shortcut symfony ở thư mục ngoài cùng của project Jobeet để giảm số kí tự phải gõ trong lệnh.
Vì thế, từ bây giờ, thay vì gõ đầy đủ đường dẫn, chúng ta chỉ cần gõ symfony.
Tạo Application
Bây giờ, tạo application frontend bằng lệnh generate:app:
$ php symfony generate:app --escaping-strategy=on --csrf-secret=Unique$ecret frontend
Một lần nữa, lệnh generate:app tạo cấu trúc thư mục mặc định cần thiết cho một application nằm trong thư mục apps/frontend:
Khi gọi lệnh generate:app , chúng ta đã cung cấp hai lựa chọn liên quan đến bảo mật:
--escaping-strategy: cho phép output escaping để chống tấn công XSS
--csrf-secret: cho phép session tokens in form để chống tấn công CSRF
Nhờ 2 tham số này, chúng ta đã bảo vệ được ứng dụng của mình khỏi 2 lỗ hổng bảo mật phổ biến trên web.
Đường dẫn symfony
Bạn có thể xem phiên bản symfony sử dụng trong dự án của bạn bằng cách gõ:
$ php symfony -V
Lệnh này cũng hiển thị đường dẫn đến thư mục cài đặt symfony, được sử dụng trong file config/ProjectConfiguration.class.php:
// config/ProjectConfiguration.class.php
require_once'/Users/fabien/work/symfony/dev/1.2/lib/autoload/sfCoreAutoload.class.php';
để cho thuận tiện, thay đường dẫn tuyệt đối bằng đường dẫn tương đối:
// config/ProjectConfiguration.class.php
require_oncedirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/
sfCoreAutoload.class.php';
Bây giờ, bạn có thể copy project Jobeet đến bất kì đâu, nó vẫn chạy được.
Môi trường
Trong thư mục web/ , bạn có thể thấy 2 file PHP: index.php và frontend_dev.php. Những file này được gọi là front controllers: mọi yêu cầu đến ứng dụng đều thông qua chúng. Nhưng tại sao chúng ta có 2 file front controllers trong khi chúng ta chỉ có một ứng dụng?
Cả hai file đều gọi cùng một ứng dụng nhưng trong những môi trường khác nhau. Khi bạn phát triển một ứng dụng, trừ khi bạn phát triển trực tiếp sản phẩm trên server, bạn cần vài môi trường:
development environment: môi trường sử dụng bởi web developers để thêm các tính năng, sửa lỗi, ...
test environment: môi trường sử dụng cho các ứng dụng test tự động.
staging environment: môi trường sử dụng bởi customer để test ứng dụng và thông báo lỗi và các tính năng thiếu.
production environment: môi trường tương tác với end user.
Trong môi trường development, ứng dụng cần log tất cả các request để dễ dàng tìm lỗi, nó phải hiển thị exception trên trình duyệt, và hệ thống cache phải được tắt để có thể thấy thay đổi khi thay đổi code. Vì thế, môi trường development phải được cấu hình cho phù hợp với lập trình viên.
Ở môi trường production, ứng dụng phải hiển thị một thông báo lỗi thay vì hiển thị lỗi cụ thể của hệ thống, và tất nhiêu, cache phải được bật. Vì thế, môi trường production phải được cấu hình cho phù hợp.
Mỗi môi trường trong symfony có một tập các cấu hình riêng và symfony có sẵn 3 môi trường: dev, test, và prod.
Nếu bạn mở các file front controller, bạn sẽ thấy chúng chỉ khác nhau về cấu hình của môi trường:
// web/index.php
<?php
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
sfContext::createInstance($configuration)->dispatch();
Cài đặt Web server
Cài đặt webserver theo cách thông thường
Trong phần trước, chúng ta đã tạo một thư mục để chứa project Jobeet. Nếu bạn tạo thư mục này dưới thư mục gốc của web server, bạn đã có thể truy cập vào project trên trình duyệt.
Thật là dễ dàng và không cần phải cấu hình gì cả! Tuy nhiên, hãy thử truy cập file config/databases.yml từ trình duyệt để hiểu tác hại của sự lười biếng này.
Không bao giờ được sử dụng cách cài đặt này trên server cho một sản phẩm thực sự và hãy đọc phần tiếp theo để biết cách cấu hình web server đúng đắn.
Cài đặt webserver theo cách bảo mật
Tốt nhất là chỉ đặt trong thư mục web root các file mà trình duyệt cần truy cập trực tiếp như stylesheets, JavaScripts, hoặc file ảnh. Mặc định, chúng tôi để những file này trong thư mục web của symfony project.
Nếu bạn xem trong thư mục này, bạn sẽ thấy vài thư mục con như css, images, js và 2 file front controller. File front controllers là file php duy nhất cần đặt trong thư mục web root. Tất cả các file PHP khác có thể ẩn đi đối với trình duyệt, để bảo mật cho ứng dụng.
Bây giờ cần thay đổi cấu hình Apache để có thể truy cập project.
Mở file cấu hình httpd.conf và thêm vào cuối file:
# Be sure to only have this line once in your configuration
NameVirtualHost 127.0.0.1:8080
# This is the configuration for Jobeet
Listen 127.0.0.1:8080
DocumentRoot "/home/sfprojects/jobeet/web"
DirectoryIndex index.php
AllowOverride All
Allow from All
Alias /sf /home/sfprojects/jobeet/lib/vendor/symfony/data/web/sf
AllowOverride All
Allow from All
Cấu hình này giúp Apache lắng nghe cổng 8080 trên máy bạn, vì thế website Jobeet có thể được truy cập được theo URL:
Bạn có thể đổi 8080 thành bất kì số nào nhưng nên lớn hơn 1024 để chắc rằng cổng này chưa được sử dụng.
Cấu hình để tạo một tên miền cho Jobeet
Nếu bạn có quyền administrator trên máy, tốt nhất là tạo một virtual hosts thay vì thêm một cổng mới mỗi khi bạn tạo một project mới. Thay vì tạo một cổng và Listen , hãy chọn một tên miền và thêm ServerName:
# This is the configuration for Jobeet
ServerName jobeet.localhost
Tên miền jobeet.localhost phải được khai báo. Nếu bạn dùng Linux, bạn cần thêm vào trong file /etc/hosts . Nếu bạn dùng Windows XP, file này nằm trong thư mục C:\WINDOWS\system32\drivers\etc\.
Thêm dòng sau: 127.0.0.1 jobeet.localhost
Kiểm tra cấu hình
Khởi động lại Apache, và kiểm tra xem bạn có thể truy cập ứng dụng từ địa chỉ hoặc tùy vào cấu hình bạn chọn ở mục trước.
Bạn có thể truy cập ứng dụng trên môi trường development:
Thanh web debug toolbar được hiển thị bên góc phải, bao gồm các biểu tượng nhỏ được cung cấp từ sf/ nếu bạn cấu hình đúng.
Subversion
Tốt nhất là sử dụng một công cụ để quản lý phiên bản của mã nguồn khi phát triển một ứng dụng web. Nó cho phép chúng ta:
làm việc với sự tin cậy
chuyển lại phiên bản trước nếu sự thay đổi gây ra lỗi
cho phép nhiều người cùng làm việc trên một project
có thể truy cập tất cả các phiên bản của ứng dụng
Trong mục này, chúng tôi sẽ mô tả cách sử dụng Subversion với symfony. Nếu bạn sử dụng công cụ quản lý mã nguồn khác, nó cũng tương tự như những gì chúng tôi hướng dẫn với Subversion.
Chúng tôi giả sử rằng bạn có quyền truy cập Subversion server.
Đầu tiên, tạo một kho chứa mới cho project jobeet:
$ svnadmin create
$ svn mkdir -m "created default directory structure"
Sau đó, xóa các file trong thư mục cache/ và log/ vì chúng ta không muốn đưa nó lên kho chứa.
$ cd /home/sfprojects/jobeet
$ rm -rf cache/*
$ rm -rf log/*
Bây giờ, chúng ta chmod để chắc chắc rằng chúng ta có quyền ghi vào thư mục cache và logs để web server của bạn có thể ghi vào đó:
$ chmod 777 cache
$ chmod 777 log
Tiếp theo, đưa mã nguồn lên kho chứa:
$ svn import -m "made the initial import" .
Chúng ta không bao giờ muốn commit những file trong thư mục cache/ và /log , nên ta đưa nó vào danh sách cần bỏ qua:
$ svn propedit svn:ignore cache
Text editor mặc định để cấu hình SVN được mở. Subversion phải bỏ qua tất cả nội dung trong thư mục:
Lưu lại vào thoát.
Làm tương tự với thư mục log/:
$ svn propedit svn:ignore log
Cuối cùng, commit những thay đổi lên kho chứa:
$ svn commit -m "added cache/ and log/ content in the ignore list"
Phát triển một dự án với symfony
Mục đích của dự án
Gần đây, người ta nói nhiều về khủng hoảng. Thất nghiệp đang tăng trở lại.
Tôi biết, những lập trình viên symfony không bị ảnh hưởng nhiều và đó là lý do bạn muốn học symfony! Nhưng thật khó để tìm một lập trình viên symfony giỏi.
Bạn có thể tìm một lập trình viên symfony ở đâu? Nơi nào để cho bạn giới thiệu kĩ năng về symfony của mình?
Bạn cần tìm một job board tốt. Thật rộng lớn? Hãy nghĩ lại. Bạn cần một nơi đăng tuyển dụng tập trung. Nơi mà bạn có thể tìm thấy chuyên gia tốt nhất. Nơi mà bạn có thể dễ dàng và nhanh chóng tìm kiếm một công việc hoặc đăng một tuyển dụng.
Không phải tìm ở đâu xa. Jobeet chính là một nơi như thế. Jobeet là một Open-Source job board chỉ làm một thứ, nhưng làm tốt. Nó dễ dàng để sử dụng, chỉnh sửa, mở rộng, và nhúng vào website khác. Nó hỗ trợ đa ngôn ngữ, và tất nhiên sử dụng những công nghệ Web 2.0 mới nhất. Nó cũng cung cấp feeds và API để tương tác với chương trình khác.
Một ứng dụng như vậy đã có chưa? Là người sử dụng, bạn sẽ tìm thấy rất nhiều nơi đăng tuyển dụng như Jobeet trên Internet. Nhưng hãy thử tìm một ứng dụng mã nguồn mở, và đầy đủ tính năng như chúng ta đã mô tả.
Kịch bản của dự án
Trước khi bắt đầu code, chúng ta hãy mô tả một chút về dự án. Phần này sẽ mô tả các tính năng mà chúng tôi muốn có trong phiên bản đầu tiên của project.
Website Jobeet có 4 loại người dùng:
admin: chủ sở hữu website và có tất cả mọi quyền
user: người vào website để tìm kiếm 1 công việc hoặc đăng tuyển dụng
poster: người đăng tuyển dụng
affiliate: người gắn tuyển dụng của Jobeet vào website của anh ta
Project có 2 application: frontend (stories F1 đến F7, bên dưới), nơi người dùng tương tác với website, và backend (stories B1 đến B3), nơi admins quản lý website.
backend được bảo mật và yêu cầu quyền truy cập.
Khi một người dùng vào website Jobeet, cô ta sẽ thấy danh sách các công việc mới nhất. Các công việc được sắp xếp theo category và ngày đưa lên (các công việc mới được đưa lên trên). Với mỗi công việc, chỉ có địa điểm (location), vị trí công việc (position), và tên công ty (company) được hiển thị.
Trong mỗi category, chỉ hiển thị danh sách 10 công việc mới nhất và một link cho phép xem danh sách tất cả các công việc của category đó(Story F2).
Ở trang chủ, người dùng có thể lọc danh sách công việc (Story F3), hoặc đăng tuyển dụng (Story F5).
Khi người dùng clicks vào tên của category hoặc vào link "more jobs" ở trang chủ, anh ta sẽ thấy được tất cả các công việc của category đó được sắp xếp theo ngày tháng.
Danh sách công việc sẽ được phân trang: 20 công việc một trang.
Người dùng có thể nhập một vài từ khóa để tìm kiếm. Từ khóa có thể được tìm theo địa điểm, vị trí công việc, theo category, hoặc tên công ty.
Người dùng có thể chọn một công việc trong danh sách để xem chi tiết.
Người dùng có thể đăng một tuyển dụng. Một công việc cần chứa các thông tin:
Tên công ty
Loại hình công việc (full-time, part-time, hay freelance)
Logo (không bắt buộc)
URL (không bắt buộc)
Vị trí công việc
Địa điểm
Category (người dùng chọn trong danh sách các category có sẵn)
Mô tả công việc (URLs và emails sẽ được tự động link)
Cách ứng tuyển (URLs và emails sẽ được tự động link)
Public (công việc có thể đưa lên websites của affiliate)
Email (email của người gửi)
Người dùng không cần tạo tài khoản cũng có thể đăng tuyển dụng.
Quá trình này được tiến hành qua 2 bước: đầu tiên, người dùng điền vào form các thông tin cần thiết về công việc, sau đó anh ta kiểm tra lại các thông tin bằng cách preview trên trang tuyển dụng.
Mặc dù người dùng không có tài khoản, nhưng vẫn có thể chỉnh sửa thông tin công việc nhờ một URL đặc biệt (dựa vào token cung cấp cho người dùng khi công việc được tạo).
Mỗi công việc sẽ xuất hiện trong 30 ngày (admin có thể sửa giá trị này - xem Story B2). Người dùng có thể kích hoạt lại hoặc tăng thời hạn công việc thêm 30 ngày nữa nhưng chỉ khi công việc đã hết hạn ít nhất 5 ngày.
Người dùng cần đăng kí để trở thành affiliate và cần xác thực để có thể sử dụng Jobeet API. Để đăng kí, anh ta phải cung cấp các thông tin:
Tên
Email
Website URL
Tài khoản affiliate phải được kích hoạt bởi admin (Story B3). Mỗi lần kích hoạt, affiliate sẽ nhận một token qua email để sử dụng API. Khi được chấp nhận, affiliate có thể chọn các công việc trong các categories. Một affiliate có thể nhận danh sách các công việc hiện tại thông qua API với token của anh ta. Danh sách công việc có thể trả về dưới dạng XML, JSON hoặc YAML. Danh sách chứa các thông tin public về công việc. Affiliate cũng có thể giới hạn số công việc trả về, và lọc theo category.
Admin có thể chỉnh sửa các categories trên website.
Anh ta cũng có thể thay đổi:
Số công việc hiển thị ở trang chủ
Ngôn ngữ của website
Thời hạn của công việc
Admin có thể sửa, xóa bất kì công việc nào. Admin có thể tạo và sửa affiliates. Anh ta chịu trách nhiệm kích hoạt tài khoản affiliate hoặc khóa tài khoản đó. Khi admin kích hoạt một tài khoản affiliate mới, hệ thống sẽ tạo một token duy nhất để affiliate sử dụng.
Data model
Để chứa jobs, affiliates, và categories, chúng ta cần một cơ sở dữ liệu quan hệ.
Nhưng symfony là một framework hướng đối tượng, chúng ta muốn thao tác với đối tượng bất cứ khi nào có thể. Ví dụ, thay vì viết câu lệnh SQL để nhận một bản ghi từ cơ sở dữ liệu, ta muốn sử dụng objects.
Thông tin về relational database phải được chuyển thành một object model. Điều đó có thể thực hiện với một ORM tool, symfony cung cấp sẵn 2 công cụ: Propel và Doctrine. Trong hướng dẫn này, chúng ta sẽ sử dụng Propel.
ORM cần thông tin mô tả các bảng và quan hệ giữa chúng để tạo class tương ứng. Có hai cách để tạo một schema mô tả: từ một cơ sở dữ liệu có sẵn hoặc tự tạo nó.
Cơ sở dữ liệu chưa tồn tại và chúng ta muốn cơ sở dữ liệu Jobeet là agnostic, do đó chúng ta tự tạo file schema config/schema.yml:
# config/schema.yml
propel:
jobeet_category:
id: ~
name: { type: varchar(255), required: true }
jobeet_job:
id: ~
category_id: { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true }
type: { type: varchar(255) }
company: { type: varchar(255), required: true }
logo: { type: varchar(255) }
url: { type: varchar(255) }
position: { type: varchar(255), required: true }
location: { type: varchar(255), required: true }
description: { type: longvarchar, required: true }
how_to_apply: { type: longvarchar, required: true }
token: { type: varchar(255), required: true, index: unique }
is_public: { type: boolean, required: true, default: 1 }
is_activated: { type: boolean, required: true, default: 0 }
email: { type: varchar(255), required: true }
expires_at: { type: timestamp, required: true }
created_at: ~
updated_at: ~
jobeet_affiliate:
id: ~
url: { type: varchar(255), required: true }
email: { type: varchar(255), required: true, index: unique }
token: { type: varchar(255), required: true }
is_active: { type: boolean, required: true, default: 0 }
created_at: ~
jobeet_category_affiliate:
category_id: { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }
affiliate_id: { type: integer, foreignTable: jobeet_affiliate, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }
File schema.yml chứa thông tin về tất cả các bảng và cột tương ứng. Mỗi cột được mô tả bao gồm:
type: kiểu dữ liệu (boolean, tinyint, smallint, integer, bigint, double, float, real, decimal, char, varchar(size), longvarchar, date, time, timestamp, blob, và clob)
required: true nếu cột đó là bắt buộc
index: true nếu bạn muốn index cho cột unique nếu bạn muốn unique index cho cột.
Với những cột được set ~ (id, created_at, và updated_at), symfony sẽ tự cấu hình phù hợp (khóa chính với id và timestamp với created_at và updated_at).
Database
Framework symfony hỗ trợ tất cả các sơ sở dữ liệu hỗ trợ PDO (MySQL, PostgreSQL, SQLite, Oracle, MSSQL, ...). PDO là database abstraction layer đi kèm trong PHP.
Chúng ta sử dụng MySQL trong bài hướng dẫn này
$ mysqladmin -uroot -pmYsEcret create jobeet
Chúng ta cần khai báo với symfony cơ sở dữ liệu ta sử dụng cho Jobeet project:
$ php symfony configure:database "mysql:host=localhost;dbname=jobeet" root mYsEcret
Lệnh configure:database có 3 tham số: PDO DSN, tên, và mật khẩu truy cập cơ sở dữ liệu. Nếu password là rỗng, hãy bỏ qua tham số này
Để tạo các bảng trong cơ sở dữ liệu, chúng ta chạy lệnh propel:insert-sql:
Do lệnh này sẽ xóa các bảng hiện tại trước khi tạo bảng mới, nên bạn được yêu cầu xác nhận hành động này. Bạn có thể thêm option --no-confirmation để bỏ qua việc xác nhận, việc này sẽ hữu ích khi bạn cần chạy lệnh một cách tự động:
$ php symfony propel:insert-sql --no-confirmation
Nhờ những mô tả về cơ sở dữ liệu trong file schema.yml , chúng ta có thể sử dụng của Propel để sinh các câu SQL cần thiết để tạo các bảng trong cơ sở dữ liệu:
$ php symfony propel:build-sql
ORM tạo các PHP classes tương ứng từ các table records sang objects:
$ php symfony propel:build-model
Lệnh propel:build-model tạo các file PHP trong thư mục lib/model dùng để tương tác với database.
Khi vào thư mục này, bạn có thể thấy rằng Propel tạo 4 class cho một table. Ví dụ với bảng jobeet_job:
JobeetJob: mỗi object của class này tương đương với một record của bảng jobeet_job. Ban đầu, class chưa có gì.
BaseJobeetJob: Lớp cha của JobeetJob. Mỗi khi bạn chạy lệnh propel:build-model, lớp này sẽ bị thay đổi, vì thế các thao tác bạn phải để trong lớp JobeetJob.
JobeetJobPeer: Lớp này chứa các static methods trả về tập các JobeetJob object. Ban đầu, class chưa có gì.
BaseJobeetJobPeer: Lớp cha của JobeetJobPeer. Mỗi khi bạn chạy lệnh propel:build-model, lớp này sẽ bị thay thế, vì thế mọi chỉnh sửa cần để trong lớp JobeetJobPeer.
Giá trị của các cột có thể được truy cập thông qua các phương thức get*() và set*():
$job = new JobeetJob();
$job->setPosition('Web developer');
$job->save();
echo $job->getPosition();
$job->delete();
Lệnh propel:build-all bao gồm các thao tác mà chúng ta đã làm. Ngoài ra, nó còn tạo ra các forms và validators cho Jobeet model classes:
$ php symfony propel:build-all
Như bạn sẽ thấy ở các phần sau, symfony tự động gọi các PHP classes, do đó bạn sẽ không bao giờ phải sử dụng require trong mã nguồn. Đó là một trong nhiều thứ mà symfony tự động làm cho lập trình viên, nhưng nó cũng có bất tiện: khi bạn thêm một class mới, bạn cần xóa symfony cache. Lệnh propel:build-model đã tạo ra rất nhiều classes mới, do đó chúng ta cần xóa cache:
$ php symfony cache:clear
Khởi tạo dữ liệu
Chúng ta đã tạo ra các bảng trong database nhưng chưa có dữ liệu. Bất kì một ứng dụng web nào đều có 3 kiểu dữ liệu:
Initial data: các dữ liệu cần thiết để ứng dụng làm việc. Ví dụ, Jobeet cần có một vài categories. Nếu không, người dùng sẽ không thể đăng tuyển dụng. Chúng ta cũng cần tạo một tài khoản admin để đăng nhập vào backend
Test data: dữ liệu test là cần thiết để test ứng dụng. Là developer, bạn cần viết test để chắc rằng ứng dụng hoạt động đúng như mô tả và cách tốt nhất là viết test tự động. Vì thế mỗi khi bạn chạy test, bạn cần một cơ sở dữ liệu với một vài dữ liệu để test.
User data: dữ liệu tạo bởi người dùng trong quá trình sử dụng ứng dụng.
Mỗi khi symfony tạo 1 bảng trong database, rất nhiều dữ liệu bị mất. Để tạo database với một vài dữ liệu khởi tạo, chúng ta có thể dùng PHP script, hoặc thực thi câu lệnh SQL. Nhưng có một cách tốt hơn trong symfony: tạo một file YAML trong thư mục data/fixtures/ và dùng lệnh 'propel:data-load` để load chúng vào database:
# data/fixtures/010_categories.yml
JobeetCategory:
design: { name: Design }
programming: { name: Programming }
manager: { name: Manager }
administrator: { name: Administrator }
# data/fixtures/020_jobs.yml
JobeetJob:
job_sensio_labs:
category_id: programming
type: full-time
company: Sensio Labs
logo: sensio_labs.png
url:
position: Web Developer
location: Paris, France
description: |
You've already developed websites with symfony and you want to work
with Open-Source technologies. You have a minimum of 3 years
experience in web development with PHP or Java and you wish to
participate to development of Web 2.0 sites using the best
frameworks available.
how_to_apply: |
Send your resume to fabien.potencier [at] sensio.com
is_public: true
is_activated: true
token: job_sensio_labs
email: job@example.com
expires_at: 2010-10-10
job_extreme_sensio:
category_id: design
type: part-time
company: Extreme Sensio
logo: extreme_sensio.png
url:
position: Web Designer
location: Paris, France
description: |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in.
Voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa
qui officia deserunt mollit anim id est laborum.
how_to_apply: |
Send your resume to fabien.potencier [at] sensio.com
is_public: true
is_activated: true
token: job_extreme_sensio
email: job@example.com
expires_at: 2010-10-10
Một file fixtures được viết bằng YAML, với mỗi model object được gán một label duy nhất. Label được sử dụng để link đến object liên quan mà không cần dùng khóa chính (khóa này tự động tăng và ta không gán giá trị cho nó). Ví dụ, công việc job_sensio_labs có category là programming, là label của category 'Programming'.
Một file fixture có thể chứa object của một hoặc vài model. Trong file fixture, bạn không cần cung cấp giá trị tất cả các cột, symfony sẽ sử dụng các giá trị mặc định trong database schema. Giá trị các cột 'created_atvàupdated_at` sẽ được tự động thêm vào. Load các dữ liệu khởi tạo vào database bằng lệnh propel:data-load:
$ php symfony propel:data-load
Xem một action trên trình duyệt
Chúng ta đã sử dụng dòng lệnh rất nhiều nhưng nó không thực sự hứng thú, đặc biệt là với một dự án web. Bây giờ chúng ta đã có mọi thứ để tạo một trang Web tương tác với database. Hãy xem cách hiển thị các công việc, chỉnh sửa một công việc, và xóa một công việc. Như đã nói trong ngày 1, một symfony project được tạo bởi các application. Mỗi application bao gồm nhiều modules. Một module là tập các mã nguồn PHP mô tả các tính năng của ứng dụng (như module API chẳng hạn), hay các thao tác của người dùng với một model object (như module job). Symfony có thể tự động tạo module cho một model với các tính năng cơ bản:
$ php symfony propel:generate-module --with-show --non-verbose-templates frontend job JobeetJob
Lệnh propel:generate-module tạo module job ở application frontend ứng với model JobeetJob. Như phần lớn các lệnh symfony khác, một vài file và thư mục được tạo trong thư mục apps/frontend/modules/job:
Bây giờ bạn có thể test module job trên trình duyệt:
Kiến trúc MVC
Nếu bạn đã từng phát triển một website bằng PHP mà không dùng framework, thường với mỗi trang HTML bạn sẽ dùng một file PHP. File PHP này sẽ chứa nhiều kiểu cấu trúc: các cấu hình khởi tạo và toàn cục, business logic liên quan đến yêu cầu của trang, lấy các dữ liệu từ database, và cuối cùng tạo mã HTML để hiển thị.
Bạn có thể sử dụng một templating engine để tách phần logic và HTML. Tất nhiên, bạn cũng có thể sử dụng một database abstraction layer để tách phần thao tác với model ra khỏi business logic. Nhưng thường bạn sẽ tạo ra rất nhiều code mà việc maintain trở thành cơn ác mộng. Có thể bạn sẽ xây dựng ứng dụng rất nhanh, nhưng thật khó để thay đổi, nâng cấp, đặc biệt khi không có ai ngoại trừ bạn hiểu được cách nó làm việc. Có một giải pháp tuyệt vời để giải quyết những vấn đề trên. Đối với việc phát triển web , giải pháp thường dùng là tổ chức code theo MVC design pattern. Pattern này chia code thành ba tầng:
Model bao gồm business logic (database nằm ở tầng này). Bạn đã thấy rằng symfony chứa tất cả các class và file liên quan đến Model trong thư mục lib/model.
View là những gì tương tác với người dùng (template engine là một phần của tầng này). Trong symfony, tầng View được tạo bởi PHP templates. Các file này nằm trong các thư mục templates khác nhau mà chúng ta sẽ thấy ở các phần sau trong ngày hôm nay.
Controller thực hiện việc lấy dữ liệu từ Model và chuyển cho View để hiển thị ở client. Khi chúng ta cài symfony trong ngày đầu tiên, chúng ta đã thấy rằng mọi yêu cầu được điều khiển bởi file front controllers (index.php và frontend_dev.php). Những file front controllers này sẽ tìm actions tương ứng để thực hiện yêu cầu đó. Như chúng ta thấy hôm qua, các action được nhóm lại trong module.
Nếu để ý, bạn sẽ thấy rằng các trang có nhiều phần giống nhau.Bạn cũng hiểu rằng việc lặp lại code thật tệ, bất kể đó là code HTML hay PHP, do đó chúng ta cần tìm cách để giảm sự lặp lại này. Một cách giải quyết là tách các header và footer thành các file riêng và include chúng vào mỗi template:
Nhưng ở đây, file header và footer không chứa valid HTML. Cần có cách tốt hơn. Thay vì reinventing the wheel, chúng ta dùng một design pattern khác để giải quyết vấn đề này: decorator design pattern. Decorator design pattern giải quyết vấn đề theo cách: sau khi nội dung chính được tạo, ta sẽ dùng một global template để thêm các phần còn lại, global template trong symfony gọi là một layout:
Một template trong symfony là một file PHP. Trong layout template, bạn sẽ thấy các PHP functions được gọi và tham chiếu đến các biến PHP. $sf_content là một biến thú vị: nó được tạo bởi framework và chứa code HTML tạo bởi một action.
Nếu bạn truy cập module job ( bạn sẽ thấy các actions bây giờ đều có layout.
Tầng View có thể cấu hình bằng cách chỉnh sửa file view.yml của application. Đây là nội dung mặc định được tạo ra sau khi dùng lệnh generate:app:
# apps/frontend/config/view.yml
default:
http_metas:
content-type: text/html
metas:
#title: symfony project
#description: symfony project
#keywords: symfony, project
#language: en
#robots: index, follow
stylesheets: [main.css]
javascripts: []
has_layout: on
layout: layout
File view.yml chứa cấu hình chung cho tất cả các templates của application. Ví dụ, phần stylesheets được xác định bởi một mảng các file stylesheet được include trong mọi trang của application (việc include được thực hiện bởi helper include_stylesheets() trong layout).
File view.yml cũng xác định layout sử dụng cho application. Mặc định, tên của nó là layout, tức là file layout.php. Bạn cũng có thể không dùng layout bằng cách chuyển giá trị của has_layout thành false.
Nguyên tắc cấu hình trong symphony: Có nhiều file cấu hình, các cấu hình giống nhau sẽ được xác định bởi các level khác nhau:
Cấu hình mặc định có giá trị trong toàn bộ framework
Cấu hình toàn cục cho project (trong thư mục config/)
Cấu hình cục bộ cho một application (trong thư mục apps/APP/config/)
Cấu hình cục bộ cho một module (trong thư mục apps/APP/modules/MODULE/config/)
Khi chạy, hệ thống sẽ xác định cấu hình từ tất cả các file này và cache lại để đảm bảo hiệu năng.
Trang chủ
Trang chủ chính là action index của module job. Action index là phần Controller của trang và liên kết với template, indexSuccess.php, là phần View:
apps/
frontend/
modules/
job/
actions/
actions.class.php
templates/
indexSuccess.php
Action
Mỗi action được tạo bởi một phương thức của một lớp. Với trang chủ, đó là lớp jobActions (tên module + Actions) và phương thức executeIndex() (execute + tên action). Nó thực hiện việc lấy tất cả các job từ database:
// apps/frontend/modules/job/actions/actions.class.php
class jobActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$this->jobeet_job_list = JobeetJobPeer::doSelect(new Criteria());
}
// ...
}
Tất cả các đối tượng này được tự động chuyển cho template (View). Để chuyển dữ liệu từ Controller cho View, hãy sử dụng $this-> :
public function executeIndex(sfWebRequest $request)
{
$this->foo = 'bar';
$this->bar = array('bar', 'baz');
}
Request và response
Khi bạn truy cập trang /job hoặc /job/show/id/1 từ trình duyệt: trình duyệt gửi một request và server trả về một response. Chúng ta đã thấy rằng symfony đóng gói request trong đối tượng sfWebRequest (xem tham số truyền vào phương thức executeShow()). Và symfony là một framework hướng đối tượng, do đó response cũng là một đối tượng, của lớp sfWebResponse. Bạn có thể truy cập đối tượng response trong action bằng cách gọi $this->getResponse(). Những đối tượng này cung cấp nhiều phương thức tiện lợi để truy cập các thông tin từ PHP functions và PHP global variables.
Tất nhiên, lớp sfWebResponse cũng cung cấp phương thức để tạo nội dung của response (setContent()) và gửi response tới trình duyệt (send()).
Ở trên, chúng ta đã biết cách quản lý stylesheets và JavaScripts từ file view.yml và templates. Ở đây, ta có thể dùng phương thức addStylesheet() và addJavascript() của đối tượng response.
Routing
Nếu bạn click xem một công việc từ trang chủ, URL sẽ kiểu như: /job/show/id/1. Nếu bạn đã từng phát triển một website bằng PHP, có lẽ bạn sẽ quen với URLs kiểu /job.php?id=1. Symfony xử lý URLs như thế nào? Làm thế nào để symfony biết được action nào được gọi dựa trên URL? Tại sao $request->getParameter('id') trả về id của job ? Hôm nay, chúng ta sẽ trả lời những câu hỏi này.
Nhưng trước tiên, chúng ta hãy nói về URLs. Trong một web context, mỗi URL xác định duy nhất một web resource. Khi bạn truy cập một URL, bạn yêu cầu trình duyệt lấy resource xác định bởi URL đó. Do URL là giao diện tương tác giữa website và người dùng, nên nó cần chứa một vài thông tin hữu ích về resource mà nó tham chiếu đến. Nhưng URLs "truyền thống" không thực sự mô tả resource, nó phơi bày ra cấu trúc bên trong của ứng dụng. Người dùng không quan tâm đến việc website được phát triển bằng ngôn ngữ nào và dữ liệu được chứa trong cơ sở dữ liệu ra sao.Việc lộ rõ cấu trúc bên trong còn tạo ra các vấn đề về bảo mật: người dùng có thể đoán được URL của các resources mà anh ta không được phép truy cập? Tất nhiên, lập trình viên phải bảo mật cho những khu vực này, nhưng tốt nhất là hãy ẩn đi các thông tin nhạy cảm.
URLs trong symfony quan trọng đến mức chúng ta có một framework riêng để quản lý chúng: routing framework. Routing quản lý internal URIs và external URLs. Khi có một request đến, routing phân tích URL và chuyển thành internal URI.
Bạn đã thấy internal URI cho trang job ở template showSuccess.php:
'job/show?id='.$job->getId()
Helper url_for() chuyển internal URI này thành URL:
/job/show/id/1
Một internal URI được tạo thành từ các phần: job là module, show là action và query string thêm tham số để gửi cho action. Cấu trúc thông dụng của một internal URIs như sau: MODULE/ACTION?key=value&key_1=value_1&...
Trong symfony, routing được tách riêng ra, bạn có thể thay đổi URLs mà không ảnh hưởng đến việc xử lý bên trong. Đó là một trong những lợi ích của front-controller design pattern.
Cấu hình routing
Sự tương ứng giữa internal URIs và external URLs được ghi trong file routing.yml:
# apps/frontend/config/routing.yml
homepage:
url: /
param: { module: default, action: index }
default_index:
url: /:module
param: { action: index }
default:
url: /:module/:action/*
File routing.yml chứa thông tin về các route. Một route bao gồm tên (homepage), pattern (/:module/:action/*), và một vài tham số (nằm sau từ khóa param).
Khi có một request, routing sẽ so sánh URL với các pattern đã có. Route tìm thấy đầu tiên sẽ được sử dụng, do đó thứ tự trong routing.yml rất quan trọng. Chúng ta sẽ xem xét vài ví dụ để hiểu rõ hơn cách hoạt động của nó. Khi bạn request trang chủ, có URL là /job , route đầu tiên phù hợp là default_index. Trong một pattern, chuỗi nằm sau dấu hai chấm (:) là một biến, vì thế pattern /:module có nghĩa là: / theo sau là một chuỗi nào đó. Trong ví dụ của chúng ta, biến module có giá trị là job. Giá trị này có thể nhận bằng cách $request->getParameter('module'). Route này cũng xác định sẵn một giá trị mặc định cho biến action. Vì thế, với mọi URLs tương ứng với route này, tham số action luôn có giá trị là index. Nếu bạn request trang /job/show/id/1, symfony sẽ match với pattern cuối cùng: /:module/:action/*. Ở pattern này, dấu (*) tương ứng với tập các cặp biến/giá trị cách nhau bởi dấu (/):
URL /job/show/id/1 có thể tạo từ template bằng helper url_for():
url_for('job/show?id='.$job->getId())
Bạn cũng có thể dùng tên của route với kí tự @ đằng trước:
url_for('@default?id='.$job->getId())
Hai cách gọi là tương đương nhưng cách gọi sau là nhanh hơn do routing không phải phân tích mọi route để tìm ra route thích hợp nhất, và nó cũng dễ khi sử dụng (không cần dùng tên module và action trong internal URI).
Route customizations
Hiện tại, khi bạn truy cập URL / từ trình duyệt, bạn sẽ thấy trang chào mừng mặc định của symfony. Đó là vì URL này matches với route homepage. Ta cần thay đổi route này thành trang chủ của Jobeet: sửa giá trị biến module thành job:
# apps/frontend/config/routing.yml
homepage:
url: /
param: { module: job, action: index }
Bây giờ, chúng ta có thể sửa lại link ở Jobeet logo trong layout dùng route homepage:
">
Thật đơn giản! Phức tạp hơn một chút, chúng ta cần đổi URL của trang job thành:
/job/sensio-labs/paris-france/1/web-developer
Không cần xem chi tiết nội dung, chỉ cần nhìn URL bạn cũng có thể biết được rằng Sensio Labs đang tìm một Web developer làm việc ở Paris, France.
Một URLs đẹp rất quan trọng bởi vì nó truyền tải thông tin đến người dùng. Nó cũng hữu dụng khi bạn copy và paste URL vào email hay optimize website cho các search engines.
Pattern dưới đây match với URL trên:
/job/:company/:location/:id/:position
Sửa file routing.yml và thêm route job vào đầu file:
job:
url: /job/:company/:location/:id/:position
param: { module: job, action: show }
Refresh lại trang chủ, link tới các job vẫn không thay đổi. Đó là vì để tạo route, bạn cần cung cấp tất cả các biến cần thiết. Vì thế, url_for() trong indexSuccess.php cần sửa lại thành:
url_for('job/show?id='.$job->getId().'&company='.$job->getCompany().
'&location='.$job->getLocation().'&position='.$job->getPosition())
Một internal URI cũng có thể viết ở dạng array:
url_for(array(
'module' => 'job',
'action' => 'show',
'id' => $job->getId(),
'company' => $job->getCompany(),
'location' => $job->getLocation(),
'position' => $job->getPosition(),
))
Test trong symfony
Có hai loại automated test trong symfony: unit tests và functional tests.
Unit test để đảm bảo rằng mỗi method và function đều hoạt động đúng. Các test phải độc lập với nhau. Còn functional test là để đảm bảo rằng kết quả trả về của ứng dụng đúng như mong đợi. Tất cả test của symfony đều nằm trong thư mục test/ của project. Nó chứa 2 thư mục con, một cho unit tests (test/unit/) và một cho functional tests (test/functional/). Unit test sẽ được đề cập đến trong ngày hôm nay, ngày mai chúng ta sẽ nói về functional test.
Unit Test
Viết unit tests có lẽ là một trong những cần thiết nhất đề có thể phát triển một ứng dụng tốt. Đối với một web developer chưa từng sử dụng test trong công việc, sẽ xuất hiện rất nhiều câu hỏi: Tôi phải viết test trước khi thực hiện một chức năng? Tôi cần test để làm gì? Test của tôi cần bao quát mọi trường hợp có thể? Làm thế nào để chắc rằng mọi thứ được test đúng? Nhưng thường có một câu hỏi cơ bản hơn: Bắt đầu như thế nào?
Mặc dù chúng tôi tán thành việc test, nhưng symfony cũng khá thực tế: có một vài test tốt hơn là không có test nào. Bạn đã viết rất nhiều code mà không có bất kì test nào? Không sao cả. Bạn không cần thiết phải có tất cả bộ test để hiểu lợi ích của việc test. Hãy bắt đầu thêm tests khi bạn tìm thấy một bug trong code của bạn. Sau đó, code của bạn sẽ trở nên tốt hơn. Bắt đầu theo cách thực dụng như vậy, bạn sẽ cảm thấy quen với việc tests hơn. Sau đó, chúng ta có thể viết test cho một tính năng mới trước khi thực hiện nó. Không lâu sau, bạn sẽ trở thành một con nghiện test :)
Một vấn đề với phần lớn các thư viện test là sự phức tạp của nó. Vì thế symfony cung cấp một thư viện test đơn giản, lime, khiến cho việc viết test trở nên dễ dàng hơn.
Tất cả unit test viết trong lime framework đều bắt đầu như sau:
require_once dirname(__FILE__).'/../bootstrap/unit.php';
$t = new lime_test(1, new lime_output_color());
Đầu tiên, file bootstrap unit.php được include để khởi tạo một vài thứ. Sau đó, một đối tượng lime_test mới được tạo ra kèm theo số lượng test dự định thực hiện.
Việc test được thực hiện bằng cách gọi một method hay một function với đầu vào xác định và so sánh kết quả trả về với kết quả mong đợi. Sự so sánh này quyết định một test là passes hay fails. Để tiện cho việc so sánh, đối tượng lime_test cung cấp một số phương thức:
Đối tượng lime_test cũng cung cấp các phương thức test tiện lợi khác:
Running Unit Test
Tất cả unit tests được chứa trong thư mục test/unit/. Thông thường, tên file test là tên của lớp mà nó cần test kèm theo cụm Test. Mặc dù bạn có thể tổ chức file trong thư mục test/unit/ như thế nào cũng được, nhưng chúng tôi khuyên bạn sử dụng cấu trúc của thư mục lib/. Tạo file test/unit/JobeetTest.php và copy đoạn code sau:
// test/unit/JobeetTest.php
require_once dirname(__FILE__).'/../bootstrap/unit.php';
$t = new lime_test(1, new lime_output_color());
$t->pass('This test always passes.');
Để chạy file test, bạn có thể gọi trực tiếp:
$ php test/unit/JobeetTest.php
Hoặc dùng lệnh test:unit
Functional Test
Functional tests là công cụ tốt để test toàn bộ ứng dụng của bạn: từ request của trình duyệt đến response trả về bởi server. Nó test mọi tầng của một ứng dụng: routing, model, actions, và templates. Việc này cũng tương tự như những gì bạn thường làm: mỗi khi bạn tạo mới hay chỉnh sửa một action, bạn cần chạy ở trình duyệt và kiểm tra xem mọi thứ có hoạt động đúng không bằng cách click vào từng link và kiểm tra kết quả trả về. Nói cách khác, bạn thực thi một kịch bản tương ứng với use case bạn đã thực hiện. Công việc này thật là nhàm chán và sẽ không kiểm soát được hết các lỗi. Mỗi khi bạn thay đổi một vài thứ trong mã nguồn, bạn phải thực thi qua tất cả các bước của kịch bản để chắc rằng chương trình hoạt động đúng. Functional tests trong symfony cung cấp một cách đơn giản để tự động mô phỏng lại các bước trong kịch bản. Giống unit tests, nó giúp code của bạn trở nên đúng đắn hơn.
Lớp sfBrouser
Trong symfony, functional tests được chạy thông qua một trình duyệt đặc biệt, implemented từ lớp sfBrowser. Nó hoạt động như một trình duyệt thực hiện ứng dụng của bạn và kết nối trực tiếp đến nó, không cần một web server. Nó cho phép bạn truy cập tất cả các symfony objects trước và sau mỗi request, giúp bạn xem xét và kiểm tra nó. sfBrowser cung cấp các phương thức giúp nó hoạt động tương tự như một trình duyệt đơn giản:
sfBrowser cũng có một vài phương thức để cấu hình cho browser behavior:
Làm việc với form
Bất kì website nào cũng có các form, từ form contact đơn giản đến các form phức tạp với rất nhiều trường. Viết code cho các form là một trong những việc rắc rối và kinh khủng đối với lập trình viên: bạn cần phải viết HTML form, thực hiện việc validation cho mỗi trường, lưu các giá trị vào trong database, hiển thị thông báo lỗi, hiển thị giá trị nhập lỗi, và còn rất nhiều việc nữa...
Tất nhiên, thay vì việc lặp lại tất cả những công việc trên, symfony cung cấp một framework để dễ dàng quản lý form. Form framework gồm 3 thành phần:
validation: validation sub-framework cung cấp các lớp để kiểm tra dữ liệu nhập vào (integer, string, email address, ...)
widgets: widget sub-framework cung cấp các lớp để trả về mã HTML (input, textarea, select, ...)
forms: các lớp form mô tả về các form được tạo từ widget và validator, và nó cũng cung cấp các phương thức để quản lý form. Mỗi form field đã bao gồm validator và widget.
Một symfony form là một lớp được tạo bởi các field. Mỗi field có tên, validator, và một widget. Một ContactForm đơn giản có thể được xác định bởi lớp sau:
class ContactForm extends sfForm
{
public function configure()
{
$this->setWidgets(array(
'email' => new sfWidgetFormInput(),
'message' => new sfWidgetFormTextarea(),
));
$this->setValidators(array(
'email' => new sfValidatorEmail(),
'message' => new sfValidatorString(array('max_length' => 255)),
));
}
}
Các form field được cấu hình trong phương thức configure(), bằng các phương thức setValidators() và setWidgets().
Tên của các lớp widget và validator rất rõ ràng: field email sẽ được render thành một HTML tag (sfWidgetFormInput) và được validate như một địa chỉ email (sfValidatorEmail). Field message sẽ được render thành một tag (sfWidgetFormTextarea), và phải là một chuỗi không có quá 255 kí tự (sfValidatorString).
Mặc định tất cả các field đều là bắt buộc, tương đương với giá trị của option required là true. Vì thế, validation cho field email tương đương với cách viết new sfValidatorEmail(array('required' => true)).
Form Action
Chúng ta đã có một form class và một template được render. Bây giờ chúng ta cần thực hiện các công việc xử lý với một vài action.
Job form được quản lý bởi 5 phương thức trong module job:
new: hiển thị form để tạo công việc
edit: hiển thị form để sửa công việc
create: tạo công việc mới khi user submit
update: sửa công việc đã có khi user submit
processForm: gọi bởi create và update, thực thi các công việc: validation, form repopulation, and serialization to the database
Các form có vòng đời như sau:
Phần quản trị
Việc đầu tiên là phải tạo backend application. Có thể bạn đã biết cách thực hiện việc này thông qua lệnh generate:app:
$ php symfony generate:app --escaping-strategy=on --csrf-secret=Unique$ecret1 backend
Mặc dù backend application chỉ được dùng bởi administrators, nhưng chúng ta vẫn enable tất cả các tính năng bảo mật có sẵn của symfony.
Admin module có nhiều tính năng hơn các module đơn giản được tạo tự động trong những ngày trước. Mặc dù không phải viết dòng code PHP nào, chúng ta cũng có đầy đủ những tính năng sau:
Hiển thị danh sách cách đối tượng có phân trang
Có thể sắp xếp danh sách
Có thể lọc danh sách
Có thể tạo, sửa, và xóa đối tượng
Có thể chọn nhiều đối tượng để cùng thực hiện một thao tác nào đó (batch)
Form nhập được validation
Hiển thị Flash messages tới user
... và nhiều tính năng khác
Admin generator cung cấp đầy đủ các tính năng bạn cần để tạo một backend interface và đơn giản trong việc cấu hình.
Giao diện và các chức năng của chương trình
4.2.1 Giao diện chính
Trang chủ
Đăng ký thành viên
(Pro
Hình ảnh
Nội thất
Giới thiệu
Trang đăng ký thành viên
Đăng Nhập
Sau khi đăng nhập
Trang giỏ hang
Đặt Hàng
Thông kê những đơn hàng đã đặt
Hình ảnh một số mẫu giấy dán tường
Trang tin nội thất
Trang quản trị
Trang quản lý tin tức
Quản lý sản phẩm
Trang quản lý người dùng
Trang quản lý hóa đơn
Trang quản lý hình ảnh
Trang nhóm sản phẩm
Phần 5. Kết luận
Trong suốt thời gian làm đồ án, bằng sự nổ lực và quyết tâm tạo ra một sản phẩm hoàn chỉnh, thân thiện với người dùng . Nhưng trong một khoảng thời gian ngắn và kinh nghiệm thực tế thiết kế một phần mềm chưa nhiều. Nên dù đã cố gắng hết sức thì phần mềm cũng mới chỉ đạt được những chức năng cơ bản nhất của người dùng yêu cầu. Và những hạn chế chưa đạt được trong phần mềm cũng còn nhiều. Hy vọng là với thời gian tới sẽ cố gắng tìm hiểu thêm và hoàn thiện sản phẩm hơn nữa.
Những điều đã làm được
Suốt quá trình học tập và thực hiện đồ án, em đã đạt được một số kết quả sau:
Tìm hiểu sâu hơn các công nghệ: PHP, MySQL và làm quen với symfony framework
Nâng cao được khả năng tự học, tự nghiên cứu cũng như các kỹ năng lập trình.
Tích lũy được nhiều kinh nghiệm trong việc thiết kế Cơ sở dữ liệu tối ưu.
Góp phần làm phong phú môi trường bán hàng trực tuyến.
Phát triển và đưa ra thiết kế giao diện trực quan, sinh động, thân thiện với người dùng.
Hạn chế:
Website chưa hỗ trợ thanh toán trực tuyến
Ngôn ngữ tiếng việt.
Hướng phát triển
Trong tương lai Website có hướng phát triển:
Hoàn thiện nội dung quản lý Website chuyên nghiệp hơn.
Thêm các chức năng cho Website (thanh toán trực tuyến…).
Phát triển , mở rộng hướng tới việc đưa Website vào hoạt động trực tuyến.
5.4 Tài liệu tham khảo
…………………
Nguyễn Trường Sinh, Nhà sách Minh Khai, Sử dụng “PHP và MySQL thiết kế Web động”.
Nguyễn Tuệ, NXB Giáo dục, Giáo trình nhập môn hệ Cơ sở dữ liệu.
Nguyễn Văn Ba, NXB Đại học Quốc gia Hà Nội, Phân tích và thiết kế hệ thống thông tin.
Jeses Castagnetto – Harish Rawat – Sascha Schumann – Chris Scollo – Deepak Veliath (1999), Professional PHP Programming
………………
Các file đính kèm theo tài liệu này:
- Bui_Manh_Khiem_51PM1_516251_DATN_fix.doc