Tóm tắt
Với những việc chúng ta đã làm ngày hôm qua, frontend application đã đầy đủ tính năng cho việc gửi công việc mới và xem danh sách công việc. Bây giờ chúng ta sẽ nói về backend application.
Hôm nay, nhờ có chức năng admin generator của symfony, chúng ta sẽ phát triển toàn bộ backend interface cho Jobeet chỉ trong 1 giờ.
Tạo Backend
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.
Backend application bây giờ đã có thể truy cập ở
http://jobeet.localhost/backend.php
đối với môi trường prod
, và
http://jobeet.localhost/backend_dev.php
với môi trường dev
.
note
Khi bạn tạo frontend application, production front controller có tên là
index.php
. Do bạn chỉ có thể có một file index.php
trong thư mục,
symfony sẽ dùng file index.php
cho production front
controller đầu tiên còn các production front controller khác thì có tên như tên application.
Nếu bạn thử reload data fixtures với lệnh doctrine:data-load
, nó
sẽ không làm việc. Đó là bởi vì phương thức JobeetJob::save()
cần truy cập
file cấu hình app.yml
từ frontend
application.
Bây giờ chúng ta có 2 application, symfony sẽ sử dụng file đầu tiên nó tìm thấy, đó là file nằm trong backend
.
Nhưng như đã nói trong ngày 8, các setting có thể được cấu hình ở các mức khác nhau.
Bằng cách chuyển nội dung từ file apps/frontend/config/app.yml
sang file
config/app.yml
, những thiết lập này có thể được chia sẻ giữa các application
khác nhau và vấn đề được giải quyết. Chúng ta sẽ dùng các class model
rất nhiều trong admin generator, vì thế chúng ta cần các biến thiết lập trong file app.yml
cho backend application.
tip
Lệnh doctrine:data-load
cũng có option --application
. Vì thế nếu bạn
cần một vài cấu hình cụ thể từ một application, bạn có thể dùng option này:
$ php symfony doctrine:data-load --application=frontend
Module Backend
Với frontend application, lệnh doctrine:generate-module
được dùng để tạo module
với các thao tác cơ bản CRUD dựa trên model class. Với backend, lệnh
doctrine:generate-admin
cũng được dùng để tạo ra backend interface với đầy đủ các chức năng ứng với một model class:
$ php symfony doctrine:generate-admin backend JobeetJob --module=job $ php symfony doctrine:generate-admin backend JobeetCategory --module=category
Hai lệnh trên tạo ra module job
và category
ứng với các class model JobeetJob
và JobeetCategory
.
Option --module
sẽ thay thế tên của module
được tạo mặc định bởi lệnh
(là jobeet_job
với lớp JobeetJob
).
Lệnh này cũng tạo route cho mỗi module:
# apps/backend/config/routing.yml jobeet_job: class: sfDoctrineRouteCollection options: model: JobeetJob module: job prefix_path: job column: id with_wildcard_routes: true
Bạn sẽ không ngạc nhiên khi thấy admin generator dùng route class
sfDoctrineRouteCollection
, do mục đích chính của một admin interface là quản lý
vòng đời của các model objet.
Route cũng có một vài option chúng ta chưa thấy trước đây:
prefix_path
: Defines the prefix path for the generated route (for instance, the edit page will be something like/job/1/edit
).column
: Defines the table column to use in the URL for links that references an object.with_wildcard_routes
: As the admin interface will have more than the classic CRUD operations, this option allows to define more object and collection actions without editing the route.
tip
Nên đọc help trước khi sử dụng một task mới.
$ php symfony help doctrine:generate-admin
Nó sẽ cung cấp cho bạn tất cả các argument và option cùng một vài ví dụ đơn giản.
Backend Look and Feel
Bây giờ, bạn có thể sử dụng các module đã được tạo ra:
http://jobeet.localhost/backend_dev.php/job http://jobeet.localhost/backend_dev.php/category
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.
Để thuận tiện cho người dùng, ta thay đổi lại layout mặc định của backend. Chúng ta sẽ thêm một menu đơn giản để dễ dàng chuyển qua lại giữa các modules khác nhau. Thay thế nội dung trong file layout.php
bằng đoạn sau:
// apps/backend/templates/layout.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Jobeet Admin Interface</title> <link rel="shortcut icon" href="/favicon.ico" /> <?php use_stylesheet('admin.css') ?> <?php include_javascripts() ?> <?php include_stylesheets() ?> </head> <body> <div id="container"> <div id="header"> <h1> <a href="<?php echo url_for('@homepage') ?>"> <img src="/legacy/images/jobeet.gif" alt="Jobeet Job Board" /> </a> </h1> </div> <div id="menu"> <ul> <li><?php echo link_to('Jobs', '@jobeet_job') ?></li> <li><?php echo link_to('Categories', '@jobeet_category') ?></li> </ul> </div> <div id="content"> <?php echo $sf_content ?> </div> <div id="footer"> <img src="/legacy/images/jobeet-mini.png" /> powered by <a href="/"> <img src="/legacy/images/symfony.gif" alt="symfony framework" /></a> </div> </div> </body> </html>
Giống như frontend, chúng tôi cũng chuẩn bị một file stylesheet đơn giản cho
backend. File admin.css
có thể
download
từ subversion tag của ngày hôm nay.
Cuối cùng, đổi lại trang chủ mặc định trong file routing.yml
:
# apps/backend/config/routing.yml homepage: url: / param: { module: job, action: index }
Symfony Cache
Nếu bạn tò mò mở những file đã được tự động tạo trong thư mục apps/backend/modules/
bạn sẽ thấy ngạc nhiên! Thư mục templates
hoàn toàn trống, và file actions.class.php
cũng không có gì:
// apps/backend/modules/job/actions/actions.class.php require_once dirname(__FILE__).'/../lib/jobGeneratorConfiguration.class.php'; require_once dirname(__FILE__).'/../lib/jobGeneratorHelper.class.php'; class jobActions extends autoJobActions { }
Làm thế nào để nó có thể hoạt động được? Nếu bạn để ý kĩ, bạn sẽ thấy rằng lớp
jobActions
thừa kế từ autoJobActions
. Lớp autoJobActions
được tự động
tạo bởi symfony nếu nó không tồn tại. Nó có thể được tìm thấy trong thư mục
cache/backend/dev/modules/autoJob/
, và chứa các module "thực sự":
// cache/backend/dev/modules/autoJob/actions/actions.class.php class autoJobActions extends sfActions { public function preExecute() { $this->configuration = new jobGeneratorConfiguration(); if (!$this->getUser()->hasCredential( $this->configuration->getCredentials($this->getActionName()) )) { // ...
Các module được tạo ra có thể được cấu hình bằng cách chỉnh sửa file config/generator.yml
trong mỗi module:
# apps/backend/modules/job/config/generator.yml generator: class: sfDoctrineGenerator param: model_class: JobeetJob theme: admin non_verbose_templates: true with_show: false singular: ~ plural: ~ route_prefix: jobeet_job with_propel_route: 1 config: actions: ~ fields: ~ list: ~ filter: ~ form: ~ edit: ~ new: ~
Mỗi khi bạn sửa file generator.yml
, symfony sẽ tạo lại cache.
Như chúng ta sẽ thấy trong hôm nay, chỉnh sửa admin generated modules là công việc dễ dàng, nhanh chóng và thú vị.
note
Việc tự động tạo lại các file cache chỉ được thực hiện trong môi trường development.
Trong môi trường production, bạn cần tự xoá cache
thông qua lệnh cache:clear
.
Cấu hình Backend
Một module trong admin có thể được cấu hình thông qua file
generator.yml
. Nội dung cấu hình được tổ chức trong 7 mục:
actions
: Default configuration for the actions found on the list and on the formsfields
: Default configuration for the fieldslist
: Configuration for the listfilter
: Configuration for the filtersform
: Configuration for the new/edit formedit
: Specific configuration for the edit pagenew
: Specific configuration for the new page
Hãy bắt đầu công việc cấu hình!
Chỉnh sửa tiêu đề
Tiêu đề của các mục list
, edit
, và new
của module category
có thể được chỉnh sửa thông qua option title
:
config: actions: ~ fields: ~ list: title: Category Management filter: ~ form: ~ edit: title: Editing Category "%%name%%" (#%%id%%) new: title: New Category
title
của mục edit
chứa vài giá trị động: tất cả các chuỗi nằm giữa
cụm %%
được thay thế bởi giá trị của các cột tương ứng.
Cấu hình cho module job
hoàn toàn tương tự:
config: actions: ~ fields: ~ list: title: Job Management filter: ~ form: ~ edit: title: Editing Job "%%company%% is looking for a %%position%% (#%%id%%)" new: title: Job Creation
Cấu hình các Field
Một field có thể là một cột trong model class, cũng có thể là một giá trị do ta tạo ra.
Cấu hình cho các field nằm trong mục fields
:
config: fields: is_activated: { label: Activated?, help: Whether the user has activated the job, or not } is_public: { label: Public? }
Mục fields
sẽ cấu hình cho các field ở tất cả các module, cấu hình trên
sẽ thay đổi label
của field is_activated
ở các trang
list
, edit
, và new
.
Cấu hình trong admin generator dựa trên nguyên lý xếp tầng. Ví dụ, nếu bạn chỉ muốn thay đổi tiêu đề trong trang list
, hãy tạo nó ở option fields
dưới mục list
:
config: list: fields: is_public: { label: "Public? (label for the list)" }
Bất kì cấu hình nào nằm dưới mục fields
chính đều có thể
được thay đổi bởi cấu hình ở từng trang cụ thể. Luật cấu hình như sau:
new
vàedit
thừa kế từform
,form
lại được thừa kế từfields
list
thừa kế từfields
filter
thừa kế từfields
note
Trong các mục về form (form
, edit
, và new
), các option label
và help
sẽ thay thế nội dung mặc định trong các lớp form.
Cấu hình trang List
display
Mặc định, trang list hiển thị tất cả các cột trong model.
Option display
sẽ thay đổi hiển thị mặc định đó bằng cách chỉ rõ cột nào được hiển thị:
config: list: title: Category Management display: [=name, slug]
Kí tự =
đặt trước cột name
sẽ tạo link cho chuỗi này.
Làm tương tự với module job
:
config: list: title: Job Management display: [company, position, location, url, is_activated, email]
layout
Trang list có thể được hiển thị trong các layout khác nhau. Mặc định là layout
tabular
, các cột sẽ được hiển thị trong một bảng.
Nhưng với module job
, ta nên sử dụng layout stacked
,
là layout khác có sẵn trong hệ thống:
config: list: title: Job Management layout: stacked display: [company, position, location, url, is_activated, email] params: | %%is_activated%% <small>%%category_id%%</small> - %%company%% (<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)
Trong layout stacked
, mỗi đối tượng được mô tả trong một chuỗi, tạo thành từ giá trị các cột
xác định trong option params
.
note
Option display
vẫn cần thiết để người dùng có thể sắp xếp danh sách theo thứ tự tăng/giảm của
từng cột.
Cột ảo
Với cấu hình trên, đoạn %%category_id%%
sẽ được thay bằng khóa chính của
category. Nhưng sẽ hữu ích hơn nếu hiển thị tên của category.
Khi bạn sử dụng kí hiệu %%
, biến trong đó không nhất thiết phải tương ứng
với một cột trong database schema. Khi đó, admin generator sẽ tìm phương thức
getter tương ứng trong model class.
Để hiển thị category name, chúng ta có thể tạo phương thức getCategoryName()
trong
class model JobeetJob
và thay thế %%category_id%%
bằng %%category_name%%
.
Nhưng lớp JobeetJob
đã có phương thức getJobeetCategory()
trả về
đối tượng category liên quan. Và nếu bạn sử dụng %%jobeet_category%%
,
nó cũng hiển thị tên category vì lớp JobeetCategory
có một magic method __toString()
trả về tên của đối tượng.
%%is_activated%% <small>%%jobeet_category%%</small> - %%company%% (<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)
sort
Là administrator, bạn sẽ muốn biết các công việc đưa lên gần đây nhất. Bạn có thể cấu hình để sắp xếp theo một cột nào đó bằng cách thêm option sort
:
config: list: sort: [expires_at, desc]
max_per_page
Mặc định, danh sách sẽ được phân trang: 20 công việc mỗi trang. Bạn có thể thay đổi nó
với option max_per_page
:
config: list: max_per_page: 10
batch_actions
Ở trang list, ta có thể thực hiện một hành động với vài đối tượng một lúc (batch action). Batch action này
là không cần thiết trong module category
, vì thế ta bỏ nó đi:
config: list: batch_actions: {}
Option batch_actions
xác định danh dách các batch action. Mảng rỗng có nghĩa là
ta bỏ mọi chức năng.
Mặc định, mỗi module có một batch action delete
tạo sẵn bởi framework,
nhưng với module job
, ta cần thêm một batch action để gia hạn cho những công việc được chọn thêm
30 ngày:
config: list: batch_actions: _delete: ~ extend: ~
Tất cả các action bắt đầu bằng _
là các action có sẵn trong framework.
Nếu bạn refresh lại trình duyệt và chọn batch action extend,
symfony sẽ hiện ra thông báo lỗi rằng bạn chưa có phương thức executeBatchExtend()
:
// apps/backend/modules/job/actions/actions.class.php class jobActions extends autoJobActions { public function executeBatchExtend(sfWebRequest $request) { $ids = $request->getParameter('ids'); $q = Doctrine_Query::create() ->from('JobeetJob j') ->whereIn('j.id', $ids); foreach ($q->execute() as $job) { $job->extend(true); $job->save(); } $this->getUser()->setFlash('notice', 'The selected jobs have been extended successfully.'); $this->redirect('@jobeet_job'); } }
Các khóa chính được chọn được chứa trong request parameter ids
. Với mỗi
công việc được chọn, phương thức JobeetJob::extend()
được gọi với một tham số
để bypass một vài kiểm tra trong phương thức. Chúng ta cần sửa lại phương thức
extend()
với tham số mới:
// lib/model/doctrine/JobeetJob.class.php class JobeetJob extends BaseJobeetJob { public function extend($force = false) { if (!$force && !$this->expiresSoon()) { return false; } $this->setExpiresAt(date('Y-m-d', time() + 86400 * sfConfig::get('app_active_days'))); $this->save(); return true; } // ... }
Sau khi tất cả các công việc đã được gia hạn, user được chuyển tới trang chủ của module job
.
object_actions
Trong trang list, có thêm một cột chứa các action bạn có thể thực hiện với từng đối tượng riêng biệt.
Với module category
, cột này là không cần thiết, do đó chúng ra có thể bỏ chúng đi:
config: list: object_actions: {}
Với module job
, chúng ta cần những action này và cần thêm một action mới extend
tương tự như batch action chúng ta đã làm:
config: list: object_actions: extend: ~ _edit: ~ _delete: ~
Tương tự như batch action, các action _delete
và _edit
được tạo sẵn bởi
framework. Chúng ta cần viết action listExtend()
để link extend
có thể làm việc:
// apps/backend/modules/job/actions/actions.class.php class jobActions extends autoJobActions { public function executeListExtend(sfWebRequest $request) { $job = $this->getRoute()->getObject(); $job->extend(true); $job->save(); $this->getUser()->setFlash('notice', 'The selected jobs have been extended successfully.'); $this->redirect('@jobeet_job'); } // ... }
actions
Chúng ta đã biết cách tạo link cho một action đối với một danh sách các đối tượng được lựa chọn, hoặc một đối tượng riêng lẻ. Option actions
xác định action không tác động đến đối tượng có sẵn nào, như: tạo một đối tượng mới. Hãy bỏ action new
có sẵn và thêm một action mới xóa tất cả các công việc không còn được activate bởi người post quá 60 ngày:
list: list: actions: deleteNeverActivated: { label: Delete never activated jobs }
Mỗi action có thể được cấu hình bằng cách xác định một mảng các tham số.
Action listDeleteNeverActivated
rất đơn giản:
// apps/backend/modules/job/actions/actions.class.php class jobActions extends autoJobActions { public function executeListDeleteNeverActivated(sfWebRequest $request) { $nb = Doctrine::getTable('JobeetJob')->cleanup(60); if ($nb) { $this->getUser()->setFlash('notice', sprintf('%d never activated jobs have been deleted successfully.', $nb)); } else { $this->getUser()->setFlash('notice', 'No job to delete.'); } $this->redirect('@jobeet_job'); } // ... }
Chúng ta đã dùng lại phương thức JobeetJobTable::cleanup()
tạo ngày hôm qua. Một lần nữa
ta lại thấy lợi ích của việc sử dụng lại trong MVC pattern.
note
bạn cũng có thể thay đổi action để thực thi bằng các cung cấp giá trị cho tham số action
:
deleteNeverActivated: { label: Delete never activated jobs, action: foo }
table_method
Số câu truy vấn cần thiết để hiển thị trang list công việc là 13, được chỉ ra trên thanh web debug toolbar.
Nếu bạn click vào số này, bạn sẽ thấy phần lớn các câu truy vấn là lấy category name cho mỗi công việc.
Để giảm số câu truy vấn, chúng ta có thể thay đối phương thức mặc định để lấy danh sách các công việc bằng cách sử dụng option
table_method
:
config: list: table_method: retrieveBackendJobList
Bây giờ, bạn cần tạo phương thức retrieveBackendJobList
trong lớp JobeetJobTable
ở lib/model/doctrine/JobeetJobTable.class.php
.
// lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { public function retrieveBackendJobList(Doctrine_Query $q) { $rootAlias = $q->getRootAlias(); $q->leftJoin($rootAlias . '.JobeetCategory c'); return $q; } // ...
Phương thức retrieveBackendJobList()
thêm join giữa bảng job
và
bảng category
và tự động tạo đối tượng category tương ứng với mỗi công việc.
Số câu truy vấn giờ giảm xuống còn 3:
Cấu hình Form
Cấu hình form nằm trong 3 mục: form
, edit
, và
new
. Các mục này có cấu hình như nhau và mục form
chỉ tồn tại như một fallback cho các mục edit
và new
.
display
Giống như trang list, bạn có thể thay đổi thứ tự hiển thị các fields với option
display
. Nhưng do form hiển thị được tạo bởi một class, nên việc bỏ một
field có thể dẫn đến lỗi khi validation.
Option display
cho form có thể dùng để nhóm các field lại trong một nhóm:
config: form: display: Content: [category_id, type, company, logo, url, position, location, description, how_to_apply, is_public, email] Admin: [_token, is_activated, expires_at]
Cấu hình trên tạo ra 2 nhóm (Content
và Admin
), mỗi nhóm chứa một số field.
Admin generator cũng hỗ trợ sẵn quan hệ nhiều-nhiều. Ở form category, bạn có một input cho trường name, một cho trường slug, và một drop-down box cho các affiliate liên quan. Chúng ta không sửa giá trị này ở trang này nên ta cần bỏ đi:
// lib/model/doctrine/JobeetCategoryForm.class.php class JobeetCategoryForm extends BaseJobeetCategoryForm { public function configure() { unset($this['jobeet_category_affiliate_list']); } }
Cột ảo
Field _token
bắt đầu bằng kí tự (_
). Điều đó có nghĩa là việc render ra field này được tạo bởi một partial do ta tự tạo _token.php
:
// apps/backend/modules/job/templates/_token.php <div class="sf_admin_form_row"> <label>Token</label> <?php echo $form->getObject()->getToken() ?> </div>
Trong partial, bạn có thể truy cập form hiện tại ($form
) và các đối tượng liên quan thông qua phương thức getObject()
.
note
Bạn cũng có thể sử dụng kết quả của một component bằng kí tự (~
) đặt trước tên field
class
Do form được sử dụng bởi administrators, chúng ta cần hiển thị nhiều thông tin hơn khi được dùng bởi user. Nhưng hiện tại, một vài thông tin không được hiển thị do chúng ta đã bỏ chúng đi trong lớp JobeetJobForm
.
Để form khác nhau giữa frontend và backend, chúng ta cần tạo 2 lớp form khác nhau.
Hãy tạo lớp BackendJobeetJobForm
thừa kế từ lớp JobeetJobForm
. Do chúng ta không có những field ẩn đi như ở frontend, nên chúng ta cần refactor lớp JobeetJobForm
bằng cách chuyển các đoạn unset()
vào một phương thức để có thể overridden trong lớp BackendJobeetJobForm
:
// lib/form/doctrine/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { $this->removeFields(); $this->validatorSchema['email'] = new sfValidatorEmail(); // ... } protected function removeFields() { unset( $this['created_at'], $this['updated_at'], $this['expires_at'], $this['token'], $this['is_activated'] ); } } // lib/form/doctrine/BackendJobeetJobForm.class.php class BackendJobeetJobForm extends JobeetJobForm { public function configure() { parent::configure(); } protected function removeFields() { unset( $this['created_at'], $this['updated_at'], $this['token'] ); } }
Lớp form mặc định dùng bởi admin generator có thể thay đổi thông qua option class
:
config: form: class: BackendJobeetJobForm
Form edit
hiện vẫn còn một vấn đề nhỏ. Logo upload lên hiện chưa được
hiển thị và bạn không thể xóa nó. Widger
sfWidgetFormInputFileEditable
thêm tính năng chỉnh sửa đối với một
input file widget:
// lib/form/doctrine/BackendJobeetJobForm.class.php class BackendJobeetJobForm extends JobeetJobForm { public function configure() { parent::configure(); $this->widgetSchema['logo'] = new sfWidgetFormInputFileEditable(array( 'label' => 'Company logo', 'file_src' => '/uploads/jobs/'.$this->getObject()->getLogo(), 'is_image' => true, 'edit_mode' => !$this->isNew(), 'template' => '<div>%file%<br />%input%<br />%delete% %delete_label%</div>', )); } // ... }
Widget sfWidgetFormInputFileEditable
có vài option cho việc tinh chỉnh các
tính năng và render:
file_src
: đường dẫn đến file được uploadis_image
: nếutrue
, ảnh sẽ được hiển thịedit_mode
: form ở chế độ edit hay khôngwith_delete
: có hiển thị checkbox delete hay khôngtemplate
: template dùng để render widget
tip
Giao diện của admin generator có thể chỉnh sửa dễ dàng do
template được tạo ra bao gồm rất nhiều class
và id
attributes. Ví dụ, có thể chỉnh sửa
field logo thông qua class sf_admin_form_field_logo
(class trong css :D). Mỗi field
cũng có một class phụ thuộc vào kiểu field như sf_admin_text
hay
sf_admin_boolean
.
Option edit_mode
sử dụng phương thức sfDoctrineRecord::isNew()
.
Nó trả về true
nếu model object của form là mới, và false
trong trường hợp ngược lại.
Nó giúp ích rất nhiều khi bạn càn có những widget hay validator khác nhau tùy vào trạng thái của đối tượng.
Cấu hình Filter
Cấu hình cho filter tương tự như cấu hình cho form. Đơn giản vì
filter chính là các form. Và các form này là các lớp được tạo thông qua lệnh
doctrine:build-all
. Bạn cũng có thể tạo lại chúng với lệnh
doctrine:build-filters
.
Các lớp form filter nằm trong thư mục lib/filter
và mỗi
model class có một filter form class tương ứng (JobeetJobFormFilter
ứng với
JobeetJobForm
).
Chúng ta không cần filter trong module category
:
config: filter: class: false
Với module job
, ta bỏ một số field:
filter: display: [category_id, company, position, description, is_activated, is_public, email, expires_at]
Do filter là không bắt buộc, nên ta không cần override lớp filter form để cấu hình hiển thị các field.
Actions Customization
Khi việc cấu hình không thỏa mãn được yêu cầu của bạn, bạn có thể thêm một phương thức mới vào action như chúng ta đã làm với tính năng extend, nhưng bạn cũng có thể override các phương thức được tạo ra:
Method | Mô tả |
---|---|
executeIndex() |
list view action |
executeFilter() |
Updates the filters |
executeNew() |
new view action |
executeCreate() |
Creates a new Job |
executeEdit() |
edit view action |
executeUpdate() |
Updates a Job |
executeDelete() |
Deletes a Job |
executeBatch() |
Executes a batch action |
executeBatchDelete() |
Executes the _delete batch action |
processForm() |
Processes the Job form |
getFilters() |
Returns the current filters |
setFilters() |
Sets the filters |
getPager() |
Returns the list pager |
getPage() |
Gets the pager page |
setPage() |
Sets the pager page |
buildCriteria() |
Builds the Criteria for the list |
addSortCriteria() |
Adds the sort Criteria for the list |
getSort() |
Returns the current sort column |
setSort() |
Sets the current sort column |
Do mỗi phương thức tạo ra chỉ thực hiện một công việc, nên việc thay đổi behavior là khá dễ dàng mà không cần copy & paste quá nhiều code.
Templates Customization
Chúng ta đã biết cách chỉnh sửa templates được tạo ra nhờ có các class
và id
attribute trong mã HTML.
Bạn cũng có thể thay thế template được tạo ra. Do template là file
PHP đơn thuần chứ không chứa lớp PHP, nên bạn có thể thay thế template bằng cách
tạo một template cùng tên trong module (ví dụ trong thư mục
apps/backend/modules/job/templates/
của admin module job
):
Template | Mô tả |
---|---|
_assets.php |
Renders the CSS and JS to use for templates |
_filters.php |
Renders the filters box |
_filters_field.php |
Renders a single filter field |
_flashes.php |
Renders the flash messages |
_form.php |
Displays the form |
_form_actions.php |
Displays the form actions |
_form_field.php |
Displays a singe form field |
_form_fieldset.php |
Displays a form fieldset |
_form_footer.php |
Displays the form footer |
_form_header.php |
Displays the form header |
_list.php |
Displays the list |
_list_actions.php |
Displays the list actions |
_list_batch_actions.php |
Displays the list batch actions |
_list_field_boolean.php |
Displays a single boolean field in the list |
_list_footer.php |
Displays the list footer |
_list_header.php |
Displays the list header |
_list_td_actions.php |
Displays the object actions for a row |
_list_td_batch_actions.php |
Displays the checkbox for a row |
_list_td_stacked.php |
Displays the stacked layout for a row |
_list_td_tabular.php |
Displays a single field for the list |
_list_th_stacked.php |
Displays a single column name for the header |
_list_th_tabular.php |
Displays a single column name for the header |
_pagination.php |
Displays the list pagination |
editSuccess.php |
Displays the edit view |
indexSuccess.php |
Displays the list view |
newSuccess.php |
Displays the new view |
Kết quả cuối cùng
Kết quả cuối cùng của việc cấu hình cho Jobeet admin:
# apps/backend/modules/job/config/generator.yml config: actions: ~ fields: is_activated: { label: Activated?, help: Whether the user has activated the job, or not } is_public: { label: Public? } list: title: Job Management layout: stacked display: [company, position, location, url, is_activated, email] params: | %%is_activated%% <small>%%JobeetCategory%%</small> - %%company%% (<em>%%email%%</em>) is looking for a %%=position%% (%%location%%) max_per_page: 10 sort: [expires_at, desc] batch_actions: _delete: ~ extend: ~ object_actions: extend: ~ _edit: ~ _delete: ~ actions: deleteNeverActivated: { label: Delete never activated jobs } table_method: retrieveBackendJobList filter: display: [category_id, company, position, description, is_activated, is_public, email, expires_at] form: class: BackendJobeetJobForm display: Content: [category_id, type, company, logo, url, position, location, description, how_to_apply, is_public, email] Admin: [_token, is_activated, expires_at] edit: title: Editing Job "%%company%% is looking for a %%position%% (#%%id%%)" new: title: Job Creation # apps/backend/modules/category/config/generator.yml config: actions: ~ fields: ~ list: title: Category Management display: [=name, slug] batch_actions: {} object_actions: {} filter: class: false form: actions: _delete: ~ _list: ~ _save: ~ edit: title: Editing Category "%%name%%" (#%%id%%) new: title: New Category
Chỉ với 2 file cấu hình, chúng ta đã phát triển một backend interface đầy đủ các tính năng cho Jobeet trong vài phút.
tip
Bạn đã biết rằng khi một thứ có thể cấu hình trong file YAML, nó cũng có thể
được cấu hình sử dụng code PHP. Với admin generator, bạn có thể sửa file
apps/backend/modules/job/lib/jobGeneratorConfiguration.class.php
.
Nó cũng có các option như file YAML nhưng thông qua code PHP.
Để biết tên của những phương thức này, hãy xem trong lớp
cache/backend/dev/modules/autoJob/lib/BaseJobGeneratorConfiguration.class.php
.
Hẹn gặp lại ngày mai
Chỉ trong một giờ, chúng ta đã xây dựng đầ đủ các tính năng của một backend interface cho Jobeet project. Để làm tất cả những việc đó, chúng ta chỉ viết chưa đến 50 dòng code PHP. Thật tuyệt!
Ngày mai, chúng ta sẽ học cách bảo mật application backend với username và password. Đồng thời, chúng ta cũng đề cập đến lớp symfony user.
This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.