Tóm tắt
Hôm qua, bạn đã phát triển ứng dụng đầu tiên của mình với symfony. Đừng dừng lại. Khi bạn học được nhiều hơn về symfony, hãy thêm những tính năng mới vào ứng dụng, đưa nó lên đâu đó, và chia sẻ với cộng đồng.
Hôm nay, chúng ta sẽ chuyển sang một vấn đề hoàn toàn mới.
Nếu bạn đang tìm kiếm một công việc, có lẽ bạn sẽ muốn được biết ngay khi công việc được đưa lên. Và thật bất tiện khi phải thường xuyên truy cập vào website để kiểm tra. Để người dùng có thể cập nhật các công việc mới ở Jobeet, hôm nay chúng ta sẽ thêm vài job feed.
Format
Symfony framework hỗ trợ sẵn vấn đề formats và mime-types. Có nghĩa là cùng một
Model và Controller có thể có các template khác nhau tùy vào format được yêu cầu.
Format mặc định là HTML nhưng symfony cũng hỗ trợ những format khác như txt
, js
, css
, json
, xml
, rdf
, và atom
.
Format có thể được set nhờ phương thức setRequestFormat()
của đối tượng request:
$request->setRequestFormat('xml');
Nhưng format thường được nhúng trong URL. Trong trường hợp này, symfony
sẽ thiết lập cho bạn dựa vào biến sf_format
dùng trong route. Với job list, URL là:
http://jobeet.localhost/frontend_dev.php/job
URL này tương đương với:
http://jobeet.localhost/frontend_dev.php/job.html
2 URL là như nhau vì route tạo bởi lớp
sfDoctrineRouteCollection
có chứa sf_format
. Bạn có thể kiểm tra điều này bằng cách
chạy lệnh app:routes
:
Feed
Feed các công việc mới nhất
Hỗ trợ các format khác nhau đơn giản là tạo các template khác nhau. Để tạo một
Atom feed cho các công việc mới nhất, ta tạo template indexSuccess.atom.php
:
<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php --> <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Jobeet</title> <subtitle>Latest Jobs</subtitle> <link href="" rel="self"/> <link href=""/> <updated></updated> <author><name>Jobeet</name></author> <id>Unique Id</id> <entry> <title>Job title</title> <link href="" /> <id>Unique id</id> <updated></updated> <summary>Job description</summary> <author><name>Company</name></author> </entry> </feed>
Mặc định, symfony sẽ thay đổi response Content-Type
tùy theo format, và với tất cả format không phải HTML, layout sẽ không được sử dụng. Với Atom
feed, symfony thay đổi Content-Type
thành application/atom+xml; charset=utf-8
Ở Jobeet footer, sửa lại link của feed:
<!-- apps/frontend/templates/layout.php --> <li class="feed"> <a href="<?php echo url_for('@job?sf_format=atom') ?>">Full feed</a> </li>
Internal URI tương tự như job
list với một biến được thêm vào sf_format
.
Thêm tag <link>
vào head ở layout:
<!-- apps/frontend/templates/layout.php --> <link rel="alternate" type="application/atom+xml" title="Latest Jobs" href="<?php echo url_for('@job?sf_format=atom', true) ?>" />
Với href
attribute của link, ta sử dụng đường dẫn tuyệt đối nhờ tham số thứ 2 của helper
url_for()
.
Sửa lại Atom template header:
<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php --> <title>Jobeet</title> <subtitle>Latest Jobs</subtitle> <link href="<?php echo url_for('@job?sf_format=atom', true) ?>" rel="self"/> <link href="<?php echo url_for('@homepage', true) ?>"/> <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime(Doctrine::getTable('JobeetJob')->getLatestPost()->getCreatedAt())) ?></updated> <author> <name>Jobeet</name> </author> <id><?php echo sha1(url_for('@job?sf_format=atom', true)) ?></id>
Ta đã dùng function strtotime()
để chuyển ngày created_at
thành timestamp. Để lấy ngày của công việc mới nhất, ta cần tạo phương thức getLatestPost()
:
// lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { public function getLatestPost() { $q = Doctrine_Query::create() ->from('JobeetJob j'); $this->addActiveJobsQuery($q); return $q->fetchOne(); } // ... }
Các feed entry được tạo bằng đoạn code sau:
<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php --> <?php use_helper('Text') ?> <?php foreach ($categories as $category): ?> <?php foreach ($category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')) as $job): ?> <entry> <title> <?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>) </title> <link href="<?php echo url_for('job_show_user', $job, true) ?>" /> <id><?php echo sha1($job->getId()) ?></id> <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime($job->getCreatedAt())) ?></updated> <summary type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <?php if ($job->getLogo()): ?> <div> <a href="<?php echo $job->getUrl() ?>"> <img src="http://<?php echo $sf_request->getHost().'/uploads/jobs/'.$job->getLogo() ?>" alt="<?php echo $job->getCompany() ?> logo" /> </a> </div> <?php endif; ?> <div> <?php echo simple_format_text($job->getDescription()) ?> </div> <h4>How to apply?</h4> <p><?php echo $job->getHowToApply() ?></p> </div> </summary> <author> <name><?php echo $job->getCompany() ?></name> </author> </entry> <?php endforeach; ?> <?php endforeach; ?>
Phương thức getHost()
của đối tượng request ($sf_request
) trả về host hiện tại, cần cho việc tạo đường dẫn tuyệt đối tới company logo.
Feed các công việc mới nhất của một Category
Một trong những mục đích của Jobeet là giúp mọi người tìm được công việc phù hợp. Vì thế, chúng ta cần cung cấp feed cho mỗi category.
Đầu tiên, sửa lại route category
để hỗ trợ các format khác:
// apps/frontend/config/routing.yml category: url: /category/:slug.:sf_format class: sfDoctrineRoute param: { module: category, action: show, sf_format: html } options: { model: JobeetCategory, type: object } requirements: sf_format: (?:html|atom)
Bây giờ, route category
đã hiểu cả format html
và atom
.
Sửa lại link tới category feed trong templates:
<!-- apps/frontend/modules/job/templates/indexSuccess.php --> <div class="feed"> <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a> </div> [php] <!-- apps/frontend/modules/category/templates/showSuccess.php --> <div class="feed"> <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a> </div>
Cuối cùng, tạo template showSuccess.atom.php
. Nhưng feed này cũng liệt kê các công việc, nên chúng ta có thể refactor mã nguồn bằng cách cho các feed entry vào trong partial _list.atom.php
. Partial bây giờ có format atom:
<!-- apps/frontend/job/templates/_list.atom.php --> <?php use_helper('Text') ?> <?php foreach ($jobs as $job): ?> <entry> <title><?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>)</title> <link href="<?php echo url_for('job_show_user', $job, true) ?>" /> <id><?php echo sha1($job->getId()) ?></id> <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime($job->getCreatedAt())) ?></updated> <summary type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <?php if ($job->getLogo()): ?> <div> <a href="<?php echo $job->getUrl() ?>"> <img src="http://<?php echo $sf_request->getHost().$job->getLogo() ?>" alt="<?php echo $job->getCompany() ?> logo" /> </a> </div> <?php endif; ?> <div> <?php echo simple_format_text($job->getDescription()) ?> </div> <h4>How to apply?</h4> <p><?php echo $job->getHowToApply() ?></p> </div> </summary> <author> <name><?php echo $job->getCompany() ?></name> </author> </entry> <?php endforeach; ?>
Bạn có thể sử dụng partial _list.atom.php
trong template job feed:
<!-- apps/frontend/modules/job/templates/indexSuccess.atom.php --> <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Jobeet</title> <subtitle>Latest Jobs</subtitle> <link href="<?php echo url_for('@job?sf_format=atom', true) ?>" rel="self"/> <link href="<?php echo url_for('@homepage', true) ?>"/> <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime(Doctrine::getTable('JobeetJob')->getLatestPost()->getCreatedAt())) ?></updated> <author> <name>Jobeet</name> </author> <id><?php echo sha1(url_for('@job?sf_format=atom', true)) ?></id> <?php foreach ($categories as $category): ?> <?php include_partial('job/list', array('jobs' => $category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')))) ?> <?php endforeach; ?> </feed>
Cuối cùng, tạo template showSuccess.atom.php
:
<!-- apps/frontend/modules/category/templates/showSuccess.atom.php --> <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Jobeet (<?php echo $category ?>)</title> <subtitle>Latest Jobs</subtitle> <link href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom'), true) ?>" rel="self" /> <link href="<?php echo url_for('category', array('sf_subject' => $category), true) ?>" /> <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime($category->getLatestPost()->getCreatedAt())) ?></updated> <author> <name>Jobeet</name> </author> <id><?php echo sha1(url_for('category', array('sf_subject' => $category), true)) ?></id> <?php include_partial('job/list', array('jobs' => $pager->getResults())) ?> </feed>
Như job feed, chúng ta cần ngày của công việc mới nhất trong một category:
// lib/model/doctrine/JobeetCategory.class.php class JobeetCategory extends BaseJobeetCategory { public function getLatestPost() { $jobs = $this->getActiveJobs(1); return $jobs[0]; } // ... }
Hẹn gặp lại ngày mai
Như nhiều tính năng khác của symfony, việc hỗ trợ sẵn các định dạng cho phép bạn thêm các feed cho website của mình mà không tốn nhiều công sức.
Hôm nay, chúng ta đã bổ sung thêm tính năng giúp người dùng dễ dàng cập nhật các công việc. Ngày mai, chúng ta sẽ nó về Web Service để cung cấp công cụ cho các job poster.
This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.