phần kế trước đã có thêm 2 bảng cơ sở dữ liệu, đương nhiên 2 bảng này và bảng categories trước đó mình thiết kế không cần khoá ngoại gì cả, bạn nào muốn thì thêm vào nhá.

Phần Thêm Truyện (table stories):

làm tương tự phần của table categories, tạo file controller, model, view, có phần này thêm nữa là một thư mục để chứa hình đại diện của một truyện, thư mục để chứa các thư mục hình ảnh mà chúng ta tạo ra sẽ là /app/webroot/img/, ở đây mình tạo thư mục stories để dễ phân biệt, mỗi 1 truyện có 1 hình đại diện nên sẽ đặt tên hình là số id của nó tương với record thêm vào trong bảng stories

Chú ý: các thư mục và file trong /app/webroot/img/ các bạn nhớ phân quyền để có thể xoá, tạo file,… mới có thể thành công trong việc upload đặt biệt là khi đưa lên hosting để chạy

Tất cả các file mình đều up lên để các bạn download nên mình không ghi chi tiết trên này.

File view: /app/View/Stories/admin_add.ctp

Chỉ thay đổi lại các input cần thiết để thêm vào bảng stories: category_id, upload(dùng để upload hình ảnh đại diện) như nói ở trên mình không lưu tên file nha, chỉ kiểm tra có upload file và file có phần mở rộng là gì sẽ được upload, các thông báo cần thiết cho việc kiểm tra nhập liệu.

File view: /app/View/Stories/admin_list.ctp

Danh sách của các truyện được thêm vào, sẽ có 2 tác vụ là Edit và Del, mình có hiển thị hình ảnh đại diện nếu được upload(phần hiển thị hình ảnh này bạn nào biết hãy kiểm tra xem file có tồn tại hay không rồi sau đó hiển thị, của mình thì mình ko có làm ^-^).

File view: /app/View/Stories/admin_edit.ctp

Nó cũng giống như file admin_add.ctp, có đều các input có thêm phần hiển thị dữ liệu nếu nó tồn tại và hiển thị hình ảnh, kiểm tra các lỗi và thông báo, Save lại để lưu các dữ liệu đã thay đổi.

File model: /app/Model/Story.php: có thêm vào đoạn như sau


public $belongsTo = array(
'Category'=>array(
'className' => 'Category',
'foreignKey' => 'category_id'
)
);

Nó dùng để lấy thêm thông tin của bảng Category mà Story thuộc vào, để lấy dữ liệu (find) có thêm tuỳ chọn ‘recursive’   => 0 chứ không phải là -1 nữa.

File Controller: /app/Controller/StoriesController.php

action list:


public function admin_list(){
   $this->set('title_for_layout', 'Story');
   $data = $this->Story->find('all', array(
     'conditions'=>array('status'=>1),
     'order' =>array('updated'=>'desc','Story.name'=>'asc'),
     'recursive' => 0
   ));
   $this->set('data', $data);
}

Các bạn sẽ thấy ‘recursive’ => 0, mặc định có sẽ là -1(chỉ lấy chính nó), 0(sẽ lấy thêm một model được chỉ định trong Model.php ở đây là Story.php) , nó còn có thể là 1 và 2 nữa nhưng mình sẽ không để cập

Khi để bằng 0 các bạn cứ hiểu nó sẽ tự động select 2 bảng dữ liệu là stories và categories(INNER JOIN), các bạn thử print_r($data) thử sẽ biết được dữ liệu trong mảng thế nào.

action add: mình đã có giải thích trong code, xin nói thêm tý về hình ảnh đại diện, mình phân tích là 1 truyện chỉ có 1 hình đại diện và là duy nhất trong table stories, cũng duy nhất trong một thư mục, nên mình sử dụng id(khoá chính) để đặt tên và phần mở rộng của nó mình mặc định nó là .jpg(phổ biến và nhẹ)


move_uploaded_file($file['tmp_name'], WWW_ROOT . 'img/stories/' . $file_name);

nó dùng để move file upload lên vào thư mục img/stories/ đã tạo sẳn và đổi tên file ảnh này lại nên nhớ cần phân quyền chính xác để có thể đọc và ghi trong thư mục này

trong action này cũng có đoạn mình kiểm tra phần mở rộng file upload lên là gì để giới hạn không cho up các file không cần thiết, đương nhiên còn rất nhiều thứ phải kiểm tra khi sử dụng upload file như dung lượng, width, height… những phần này mình sẽ có 1 bài upload file trong CakePHP riêng.

action edit: lấy dữ liệu của thể loại truyện(categories) và dữ liệu của truyện(stories) để hiện thì ngoài input của view, kiểm tra có upload hình ảnh hay không, nếu không thì không cần làm gì chỉ việc save dữ liệu, nếu có upload ảnh thì kiểm tra các bước cần thiết sau đó move_upload_file() và tên thì cứ đặt là id của truyện edit, nó sẽ ghi đè hình ảnh đang có(cần phần quyền)

action delete thì chỉ xoá đi dữ liệu tương ứng được chọn, chú ý là đã xoá truyện rùi thì nên xoá luôn hình đại diện nha.


@unlink(WWW_ROOT.'img'.DS.'stories'.DS.$id.'.jpg');

đây là đoạn để xoá tấm ảnh, DS chính là dấu ‘/’ trong cakephp, dấu @ là để ẩn cảnh báo nếu không tồn tại ảnh, bạn không thích để @ thì hay kiểm tra file ảnh có tồn tại trong thư mục hay không rùi hãy xoá, mình thì dùng đơn giản ở trên thôi.

Phần thêm các tập trong truyện(table chapters)

Xin nói sơ qua ý tưởng để hiển thị các chap(tập) trong một truyện, thông thường 1 truyện sẽ có nhiều chap, và mỗi 1 chap sẽ có tên và các hình ảnh (khoảng 10 – 20 hình gì đó), đối với những hình ảnh này các bạn thử hình dung một truyện mà mình hâm mộ đây (One Pice) hiện tại bây giờ đã có 862 chap và mỗi chap có 20 tấm ảnh thì các bạn thử xem có bao nhiêu tấm ảnh cho một truyện, và nhiều truyện thì thế nào, dung lượng chứa rất ư là lớn không khả thi khi lấy server mình để chứa hình ảnh, và hầu hết các trang web đọc truyện tranh hiện nay cũng thế đều lưu ảnh ở các host khác, các dịch vụ upload ảnh free hoặc tính phí gì đó, sau đó sẽ lấy link và hiển thị trên website của mình, ở đây mình cũng làm vậy. Nhưng công đoạn upload ảnh này các bạn tự mình làm nha, nó cũng có nhiều hướng dẫn lắm. Link ảnh mình sẽ lấy mượn của một trang web khác.

File view: /app/View/Chapters/admin_add.ctp

Cũng không khác gì các file view add khác, ở đây có input link_img là các link ảnh đã upload từ host khác, mỗi một tấm ảnh là 1 link, ở đây mình lưu dưới dạng text, ngăn cách mỗi tấm ảnh là dấu #, nó tạo thành một chuỗi như sau: hinh1#hinh2#hinh3#hinh4 .Như vậy khi lấy dc chuỗi trên ta sẽ có được mảng các tấm ảnh trong một chap, chỉ cần foreach để lấy dữ liệu thui.

Chú ý khi nhập liệu phần này(hướng dẫn lấy link truyện thủ công)

Bạn truy cập vào một trang truyện nào đó, vào một truyện bất kỳ muốn lấy, rùi vào chap để đọc luôn, nó sẽ ra 1 page toàn ảnh cho bạn đọc, nhấn chuột phải vào màn hình web đọc truyện chọn Inspect (Kiểm tra phần tử)

Screen Shot 2017-04-19 at 11.22.53 AM

Đến đây chúng ta có thể thấy 1 loạt các tấm ảnh như sau:

Screen Shot 2017-04-19 at 11.25.28 AM

Tiến hành copy các link hình đó về và phân cách chúng bằng dấu # để tạo thành 1 chuỗi, ví dụ trên mình sẽ có được một chuỗi :


http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36FKyKRtI/AAAAAAAADNA/c91pz_es7Tw/s0/Chuong_001-OP01-00.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36F6K8-LI/AAAAAAAADNM/torkW5limjw/s0/Chuong_001-OP01-01.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36GhEMhZI/AAAAAAAADNY/so64eQU23xQ/s0/Chuong_001-OP01-02-03.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36HSJqTmI/AAAAAAAADNk/Vbhw3weHk-M/s0/Chuong_001-OP01-04.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36IIGhCCI/AAAAAAAADN0/3yKOzu3iES8/s0/Chuong_001-OP01-05.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36It7RIiI/AAAAAAAADOA/FqyM8VODgT8/s0/Chuong_001-OP01-06.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36JWzWjwI/AAAAAAAADOM/is-H8V0VuSo/s0/Chuong_001-OP01-07.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36LGpCYYI/AAAAAAAADOg/SKqp-muWZ8o/s0/Chuong_001-OP01-08.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36L4W0sAI/AAAAAAAADOs/zAoTkWBeAq8/s0/Chuong_001-OP01-09.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36NTH_I1I/AAAAAAAADO8/mXJ0k94hu7E/s0/Chuong_001-OP01-10.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36On5R8tI/AAAAAAAADPI/ynsdrnR5z2k/s0/Chuong_001-OP01-11.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36PJEc39I/AAAAAAAADPU/wV-j7bfiOuc/s0/Chuong_001-OP01-12.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36P04cXGI/AAAAAAAADPg/YTb2CfSh18g/s0/Chuong_001-OP01-13.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36Qn08J8I/AAAAAAAADPs/VeyUFGqIhsw/s0/Chuong_001-OP01-14.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36Rtq6nxI/AAAAAAAADPw/2baj2uPXjIM/s0/Chuong_001-OP01-15.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36SXXE5bI/AAAAAAAADP4/EE8t0WewTKs/s0/Chuong_001-OP01-16.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36S4p10dI/AAAAAAAADQE/LdhwVi2n_CI/s0/Chuong_001-OP01-17.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36Tk08NsI/AAAAAAAADQQ/8XbFQD0M5Nc/s0/Chuong_001-OP01-18.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36UdM8W6I/AAAAAAAADQc/O8Cn-970rWc/s0/Chuong_001-OP01-19.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36VJK3aMI/AAAAAAAADQw/2rNEyRPCguc/s0/Chuong_001-OP01-20.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36WG4Xj-I/AAAAAAAADRI/m1PTiHJ1DTg/s0/Chuong_001-OP01-21.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36XMNDHkI/AAAAAAAADRU/8e4lIuNfWMw/s0/Chuong_001-OP01-22.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36X6qJiNI/AAAAAAAADRk/z0Guvd8loZE/s0/Chuong_001-OP01-23.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36Y0zKEFI/AAAAAAAADRw/AoBVs2G9WQ8/s0/Chuong_001-OP01-24.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36ZpHJ_eI/AAAAAAAADR8/uLElHbov1_4/s0/Chuong_001-OP01-25.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36aXYLvaI/AAAAAAAADSM/Ezn1ZwL3O1c/s0/Chuong_001-OP01-26.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36bBfcygI/AAAAAAAADSY/xCD1QRXODGI/s0/Chuong_001-OP01-27.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36b8TQD3I/AAAAAAAADSk/6-2useWJpj0/s0/Chuong_001-OP01-28.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36cYGKmDI/AAAAAAAADS0/4YnAzZImMG0/s0/Chuong_001-OP01-29.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36dFSoTdI/AAAAAAAADTA/CE2A2LmRRIk/s0/Chuong_001-OP01-30.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36eH_uYnI/AAAAAAAADTM/hC7NnuD1hE4/s0/Chuong_001-OP01-31.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36ep4-reI/AAAAAAAADTc/NrKjqrTo1-4/s0/Chuong_001-OP01-32.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36fVPXJGI/AAAAAAAADTo/fDf3YQvLJ3E/s0/Chuong_001-OP01-33.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36gC83DjI/AAAAAAAADT0/9eDiQRvTeR0/s0/Chuong_001-OP01-34.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36gz_KzII/AAAAAAAADUE/0RIY38S6KMI/s0/Chuong_001-OP01-35.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36hXpObDI/AAAAAAAADUQ/MLcVZESMd7w/s0/Chuong_001-OP01-36.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36iL61ysI/AAAAAAAADUg/n8CPopEyc5o/s0/Chuong_001-OP01-37.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36jDJt8yI/AAAAAAAADUs/89r6Ogksrts/s0/Chuong_001-OP01-38.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36kL6YQnI/AAAAAAAADU8/1ebzF9rVgs8/s0/Chuong_001-OP01-39.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36k5ylHuI/AAAAAAAADVI/M974yk-83eY/s0/Chuong_001-OP01-40.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36mHerwlI/AAAAAAAADVU/g5AK7-t_-zE/s0/Chuong_001-OP01-41.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36m775t6I/AAAAAAAADVY/6KmJsDyh55o/s0/Chuong_001-OP01-42.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36pTQ5b4I/AAAAAAAADVo/7RBwsRgRPp4/s0/Chuong_001-OP01-43.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36qNIqQJI/AAAAAAAADV0/0U5yKvBOBTU/s0/Chuong_001-OP01-44.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36qlB6vEI/AAAAAAAADWE/mxjYL27xB9c/s0/Chuong_001-OP01-45.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36rVDJvsI/AAAAAAAADWQ/J3FEQaZnhFA/s0/Chuong_001-OP01-46.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36sOpApfI/AAAAAAAADWg/7Er_KvAA_-A/s0/Chuong_001-OP01-47.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36s4rU8_I/AAAAAAAADWw/pHPt9itxzXI/s0/Chuong_001-OP01-48.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36tuaXohI/AAAAAAAADW8/KGHr_Nun5WQ/s0/Chuong_001-OP01-49.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36up2DEwI/AAAAAAAADXE/2_CmkueoHis/s0/Chuong_001-OP01-50-51.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36vcutyrI/AAAAAAAADXg/06x4rqFqdgU/s0/Chuong_001-OP01-52.jpg#http://2.bp.blogspot.com/_BW4Xi0F0vXI/Tc36wJebeDI/AAAAAAAADXs/lgc0iiESzUA/s0/Chuong_001-OP01-53.jpg

dán hết đoạn trên vào Link_img rùi save lại chúng ta sẽ có được một chap có hình ảnh đầy đủ, hãy sử dụng nút Review trong trang danh sách để xem các hình ảnh của mình sau khi thực hiện

Chú ý: nhiều trang web các bạn có thể thấy link ảnh, và copy về để vào web mình nhưng nó không chạy, lý do là vì những ảnh đó họ không public ra ngoài, các bạn cứ tìm nguồn khác và copy lại, rất nhiều nguồn để copy mà.

File view: /app/View/Chapters/admin_list.ctp chỉ là hiển thị danh sách các chap.

File view: /app/View/Chapters/admin_review.ctp xem lại các hình ảnh đã thêm vào chap.

File view: /app/View/Chapters/admin_edit.ctp cập nhật lại các thông tin mà chap được chọn.

File model: /app/Model/Chapter.php: cũng có đoạn để xác định lấy dữ liệu có sử dụng JOIN hay không:


public $belongsTo = array(
'Story'=>array(
'className' => 'Story',
'foreignKey' => 'story_id'
)
);

File Controller: /app/Controller/ChaptersController.php

Mọi action tương ứng cho các view, các bạn tham khảo trong file tải về, vì mình cũng không biết nói gì nữa, đã nói ở trên hết rồi. ^-^

Các bạn tải về và xem code của mình, không hiểu thì comment trong bài viết mình sẽ hỗ trợ thêm. Ở đây mình đưa lại các CSDL đã có cho các bạn cập nhật mới.

Phần tiếp theo: sẽ là phần cấu hình thêm các biến sử dụng chung, các define, viết 1 Component Data, hỗ trợ lấy hình, rút gọn link, … hy vọng các bạn theo dõi cùng nongdanit

Kết luận

  1. Nếu có thắc mắc gì các bạn để lại comment bên dưới mình sẽ trả lời sớm nhất có thể.
  2. Cảm ơn các bạn đã đọc.

Nongdanit.info
[Cakephp] Bài 27 – Toàn tập website truyện tranh phần 6
Tagged on: