PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/jobeet/it/14.markdown

https://github.com/rafaelgou/symfony1-docs
Markdown | 418 lines | 347 code | 71 blank | 0 comment | 0 complexity | 82207d338a519e7b44f29a2010a73ffa MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. Giorno 14: Feed
  2. ===============
  3. Ieri avete iniziato a sviluppare la vostra prima applicazione con symfony.
  4. Non fermatevi adesso. Come imparate qualcosa di nuovo su symfony provate
  5. ad aggiungere nuove feature alla vostra applicazione, rendetela pubblica
  6. e condividetela con la comunità.
  7. Passiamo oggi a qualcosa di completamente diverso.
  8. Se state cercando un lavoro molto probabilmente vorreste essere informati
  9. ogni volta che un'offerta viene inserita. Poiché controllare il sito web
  10. ogni ora non è molto conveniente, oggi aggiungeremo molti feed, per tenere
  11. aggiornati gli utenti di Jobeet.
  12. Formati
  13. -------
  14. Il framework symfony ha un supporto nativo per ~formati|Formati~ e ~tipi mime|Tipi mime~. Questo
  15. significa che gli stessi Model e Controller possono avere diversi ~template|Template~
  16. in base al formato richiesto. Il formato di default è HTML, tuttavia symfony
  17. supporta molti altri ~formati in modo nativo|Formati nativi~ come `txt`, `js`, `css`, `json`,
  18. `xml`, `rdf` o `atom`.
  19. Il formato può essere impostato usando il metodo `setRequestFormat()`
  20. dell'oggetto ~richiesta|Richiesta HTTP~:
  21. [php]
  22. $request->setRequestFormat('xml');
  23. Il più delle volte il formato è integrato nell'URL. In questo caso symfony
  24. lo imposterà per voi se la variabile speciale ~`sf_format`~ è utilizzata
  25. nella corrispondente rotta. Per la lista delle offerte l'URL è:
  26. http://jobeet.localhost/frontend_dev.php/job
  27. Questo URL è equivalente a:
  28. http://jobeet.localhost/frontend_dev.php/job.html
  29. Entrambi gli URL sono equivalenti perché le rotte generate dalla classe
  30. `sfPropelRouteCollection` hanno `sf_format` come estensione e perché
  31. il formato standard è `html`. Potete verificarlo personalmente
  32. utilizzando il task `app:routes`.
  33. ![Cli](http://www.symfony-project.org/images/jobeet/1_4/15/cli.png)
  34. Feed
  35. ----
  36. ### Feed Ultime Offerte di Lavoro
  37. Supportare diversi formati è semplice quanto creare diversi template. Per
  38. creare un [Atom feed](http://en.wikipedia.org/wiki/Atom_(standard)) per
  39. le ultime offerte inserite, create il template `indexSuccess.atom.php`:
  40. [php]
  41. <!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
  42. <?xml version="1.0" encoding="utf-8"?>
  43. <feed xmlns="http://www.w3.org/2005/Atom">
  44. <title>Jobeet</title>
  45. <subtitle>Latest Jobs</subtitle>
  46. <link href="" rel="self"/>
  47. <link href=""/>
  48. <updated></updated>
  49. <author><name>Jobeet</name></author>
  50. <id>Unique Id</id>
  51. <entry>
  52. <title>Job title</title>
  53. <link href="" />
  54. <id>Unique id</id>
  55. <updated></updated>
  56. <summary>Job description</summary>
  57. <author><name>Company</name></author>
  58. </entry>
  59. </feed>
  60. >**SIDEBAR**
  61. >Nomi dei template
  62. >
  63. >Siccome `html` è il formato più comune per le applicazioni web può essere
  64. >omesso dai nomi dei template. Sia `indexSuccess.php` che `indexSuccess.html.php`
  65. >sono equivalenti e symfony usa il primo che trova.
  66. >
  67. >Perché i template di default hanno come suffisso `Success`? Un'azione può restituire
  68. >un valore per indicare quale template usare. Se l'azione non restituisce nulla,
  69. >è equivalente al seguente codice:
  70. >
  71. > [php]
  72. > return sfView::SUCCESS; // == 'Success'
  73. >
  74. >Se volete cambiare il suffisso basta tornare qualcosa di diverso:
  75. >
  76. > [php]
  77. > return sfView::ERROR; // == 'Error'
  78. >
  79. > return 'Foo';
  80. >
  81. >Come abbiamo visto in un giorno precedente, si può inoltre cambiare il
  82. >nome del template usando il metodo `setTemplate()`:
  83. >
  84. > [php]
  85. > $this->setTemplate('foo');
  86. Di default symfony cambia la risposta `~Content-Type~` in accordo al formato,
  87. per tutti i formati non-HTML il layout viene disabilitato. Per un feed Atom
  88. symfony cambia il `Content-Type` a `application/atom+xml; charset=utf-8`.
  89. Nel footer di Jobeet aggiornate il link del feed:
  90. [php]
  91. <!-- apps/frontend/templates/layout.php -->
  92. <li class="feed">
  93. <a href="<?php echo url_for('@job?sf_format=atom') ?>">Full feed</a>
  94. </li>
  95. L'~URI interno~ è lo stesso che per la lista `job` con il `sf_format` aggiunto
  96. come variabile.
  97. Aggiungete un `<link>` tag nell'head del layout, per consentire la
  98. scoperta automatica dei feed da parte del browser:
  99. [php]
  100. <!-- apps/frontend/templates/layout.php -->
  101. <link rel="alternate" type="application/atom+xml" title="Latest Jobs"
  102. href="<?php echo url_for('@job?sf_format=atom', true) ?>" />
  103. Per l'attributo `href` link viene usato un ~URL assoluto~, grazie al secondo
  104. parametro dell'helper `url_for()`.
  105. Sostituiamo l'header del template Atom col codice seguente:
  106. [php]
  107. <!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
  108. <title>Jobeet</title>
  109. <subtitle>Latest Jobs</subtitle>
  110. <link href="<?php echo url_for('@job?sf_format=atom', true) ?>" rel="self"/>
  111. <link href="<?php echo url_for('@homepage', true) ?>"/>
  112. <propel>
  113. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', JobeetJobPeer::getLatestPost()->getCreatedAt('U')) ?></updated>
  114. </propel>
  115. <doctrine>
  116. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', Doctrine::getTable('JobeetJob')->getLatestPost()->getDateTimeObject('created_at')->format('U')) ?></updated>
  117. </doctrine>
  118. <author>
  119. <name>Jobeet</name>
  120. </author>
  121. <id><?php echo sha1(url_for('@job?sf_format=atom', true)) ?></id>
  122. <propel>
  123. Notate l'utilizzo di `U` come parametro di `getCreatedAt()` per ottenere la
  124. data come timestamp. Per avere la data dell'ultimo post, create il metodo
  125. `getLatestPost()`:
  126. </propel>
  127. <doctrine>
  128. Notate l'utilizzo di `U` come parametro di `format()` per ottenere
  129. la data come timestamp. Per avere la data dell'ultimo post, create il metodo
  130. `getLatestPost()`:
  131. </doctrine>
  132. <propel>
  133. [php]
  134. // lib/model/JobeetJobPeer.php
  135. class JobeetJobPeer extends BaseJobeetJobPeer
  136. {
  137. static public function getLatestPost()
  138. {
  139. $criteria = new Criteria();
  140. self::addActiveJobsCriteria($criteria);
  141. return JobeetJobPeer::doSelectOne($criteria);
  142. }
  143. // ...
  144. }
  145. </propel>
  146. <doctrine>
  147. [php]
  148. // lib/model/doctrine/JobeetJobTable.class.php
  149. class JobeetJobTable extends Doctrine_Table
  150. {
  151. public function getLatestPost()
  152. {
  153. $q = Doctrine_Query::create()
  154. ->from('JobeetJob j');
  155. $this->addActiveJobsCriteria($q);
  156. return $q->fetchOne();
  157. }
  158. // ...
  159. }
  160. </doctrine>
  161. I dati del feed possono essere generati con il seguente codice:
  162. [php]
  163. <!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
  164. <?php use_helper('Text') ?>
  165. <?php foreach ($categories as $category): ?>
  166. <?php foreach ($category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')) as $job): ?>
  167. <entry>
  168. <title>
  169. <?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>)
  170. </title>
  171. <link href="<?php echo url_for('job_show_user', $job, true) ?>" />
  172. <id><?php echo sha1($job->getId()) ?></id>
  173. <propel>
  174. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $job->getCreatedAt('U')) ?></updated>
  175. </propel>
  176. <doctrine>
  177. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $job->getDateTimeObject('created_at')->format('U')) ?></updated>
  178. </doctrine>
  179. <summary type="xhtml">
  180. <div xmlns="http://www.w3.org/1999/xhtml">
  181. <?php if ($job->getLogo()): ?>
  182. <div>
  183. <a href="<?php echo $job->getUrl() ?>">
  184. <img src="http://<?php echo $sf_request->getHost().'/uploads/jobs/'.$job->getLogo() ?>"
  185. alt="<?php echo $job->getCompany() ?> logo" />
  186. </a>
  187. </div>
  188. <?php endif; ?>
  189. <div>
  190. <?php echo simple_format_text($job->getDescription()) ?>
  191. </div>
  192. <h4>How to apply?</h4>
  193. <p><?php echo $job->getHowToApply() ?></p>
  194. </div>
  195. </summary>
  196. <author>
  197. <name><?php echo $job->getCompany() ?></name>
  198. </author>
  199. </entry>
  200. <?php endforeach; ?>
  201. <?php endforeach; ?>
  202. Il metodo `getHost()` dell'oggetto request (`$sf_request`) restituisce
  203. l'host corrente, che torna utile per creare un link assoluto per il
  204. logo della società.
  205. ![Feed](http://www.symfony-project.org/images/jobeet/1_4/15/feed.png)
  206. >**TIP**
  207. >Creando un feed, il ~debug|Debug~ è più semplice se si usano gli strumenti da
  208. >linea di comando come
  209. >[`curl`](http://curl.haxx.se/) o
  210. >[`wget`](http://www.gnu.org/software/wget/), in modo da vedere
  211. >l'attuale contenuto del feed.
  212. ### Feed delle ultime offerte in una categoria
  213. Uno degli scopi di Jobeet è quello di aiutare le persone a trovare lavori
  214. più specializzati. Quindi abbiamo bisogno di fornire un ~feed|Feed~ per ogni categoria.
  215. Primo, aggiorniamo la rotta `category` per aggiungere il supporto per i
  216. differenti formati:
  217. [yml]
  218. // apps/frontend/config/routing.yml
  219. category:
  220. url: /category/:slug.:sf_format
  221. class: sfPropelRoute
  222. param: { module: category, action: show, sf_format: html }
  223. options: { model: JobeetCategory, type: object }
  224. requirements:
  225. sf_format: (?:html|atom)
  226. Ora la rotta `category` può capire entrambi i formati `html` e `atom`.
  227. Aggiornate i link ai feed di categoria nei ~template|Template~:
  228. [php]
  229. <!-- apps/frontend/modules/job/templates/indexSuccess.php -->
  230. <div class="feed">
  231. <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a>
  232. </div>
  233. <!-- apps/frontend/modules/category/templates/showSuccess.php -->
  234. <div class="feed">
  235. <a href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom')) ?>">Feed</a>
  236. </div>
  237. L'ultimo passo è creare il template `showSuccess.atom.php`. Ma visto che
  238. questo feed dovrà elencare le offerte di lavoro possiamo ~rifattorizzare|Rifattorizzare~
  239. il codice che genera i dati per il feed creando un partial `_list.atom.php`.
  240. Come per il formato `html` i ~partial|Partial~ sono specifici per il formato:
  241. [php]
  242. <!-- apps/frontend/modules/job/templates/_list.atom.php -->
  243. <?php use_helper('Text') ?>
  244. <?php foreach ($jobs as $job): ?>
  245. <entry>
  246. <title><?php echo $job->getPosition() ?> (<?php echo $job->getLocation() ?>)</title>
  247. <link href="<?php echo url_for('job_show_user', $job, true) ?>" />
  248. <id><?php echo sha1($job->getId()) ?></id>
  249. <propel>
  250. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $job->getCreatedAt('U')) ?></updated>
  251. </propel>
  252. <doctrine>
  253. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', strtotime($job->getCreatedAt())) ?></updated>
  254. </doctrine>
  255. <summary type="xhtml">
  256. <div xmlns="http://www.w3.org/1999/xhtml">
  257. <?php if ($job->getLogo()): ?>
  258. <div>
  259. <a href="<?php echo $job->getUrl() ?>">
  260. <img src="http://<?php echo $sf_request->getHost().$job->getLogo() ?>" alt="<?php echo $job->getCompany() ?> logo" />
  261. </a>
  262. </div>
  263. <?php endif; ?>
  264. <div>
  265. <?php echo simple_format_text($job->getDescription()) ?>
  266. </div>
  267. <h4>How to apply?</h4>
  268. <p><?php echo $job->getHowToApply() ?></p>
  269. </div>
  270. </summary>
  271. <author>
  272. <name><?php echo $job->getCompany() ?></name>
  273. </author>
  274. </entry>
  275. <?php endforeach; ?>
  276. Potete usare il partial `_list.atom.php` per semplificare il template del feed
  277. delle offerte:
  278. [php]
  279. <!-- apps/frontend/modules/job/templates/indexSuccess.atom.php -->
  280. <?xml version="1.0" encoding="utf-8"?>
  281. <feed xmlns="http://www.w3.org/2005/Atom">
  282. <title>Jobeet</title>
  283. <subtitle>Latest Jobs</subtitle>
  284. <link href="<?php echo url_for('@job?sf_format=atom', true) ?>" rel="self"/>
  285. <link href="<?php echo url_for('@homepage', true) ?>"/>
  286. <propel>
  287. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', JobeetJobPeer::getLatestPost()->getCreatedAt('U')) ?></updated>
  288. </propel>
  289. <doctrine>
  290. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', Doctrine::getTable('JobeetJob')->getLatestPost()->getDateTimeObject('created_at')->format('U')) ?></updated>
  291. </doctrine>
  292. <author>
  293. <name>Jobeet</name>
  294. </author>
  295. <id><?php echo sha1(url_for('@job?sf_format=atom', true)) ?></id>
  296. <?php foreach ($categories as $category): ?>
  297. <?php include_partial('job/list', array('jobs' => $category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')))) ?>
  298. <?php endforeach; ?>
  299. </feed>
  300. Infine create il template `showSuccess.atom.php`:
  301. [php]
  302. <!-- apps/frontend/modules/category/templates/showSuccess.atom.php -->
  303. <?xml version="1.0" encoding="utf-8"?>
  304. <feed xmlns="http://www.w3.org/2005/Atom">
  305. <title>Jobeet (<?php echo $category ?>)</title>
  306. <subtitle>Latest Jobs</subtitle>
  307. <link href="<?php echo url_for('category', array('sf_subject' => $category, 'sf_format' => 'atom'), true) ?>" rel="self" />
  308. <link href="<?php echo url_for('category', array('sf_subject' => $category), true) ?>" />
  309. <propel>
  310. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $category->getLatestPost()->getCreatedAt('U')) ?></updated>
  311. </propel>
  312. <doctrine>
  313. <updated><?php echo gmstrftime('%Y-%m-%dT%H:%M:%SZ', $category->getLatestPost()->getDateTimeObject('created_at')->format('U')) ?></updated>
  314. </doctrine>
  315. <author>
  316. <name>Jobeet</name>
  317. </author>
  318. <id><?php echo sha1(url_for('category', array('sf_subject' => $category), true)) ?></id>
  319. <?php include_partial('job/list', array('jobs' => $pager->getResults())) ?>
  320. </feed>
  321. Come per il feed principale abbiamo bisogno della data dell'ultima offerta inserita
  322. per una categoria:
  323. [php]
  324. <propel>
  325. // lib/model/JobeetCategory.php
  326. </propel>
  327. <doctrine>
  328. // lib/model/doctrine/JobeetCategory.class.php
  329. </doctrine>
  330. class JobeetCategory extends BaseJobeetCategory
  331. {
  332. public function getLatestPost()
  333. {
  334. $jobs = $this->getActiveJobs(1);
  335. return $jobs[0];
  336. }
  337. // ...
  338. }
  339. ![Category Feed](http://www.symfony-project.org/images/jobeet/1_4/15/category_feed.png)
  340. A domani
  341. --------
  342. Come per molte feature di symfony il supporto nativo vi permette di aggiungere
  343. feed al proprio sito, senza particolari sforzi.
  344. Oggi abbiamo migliorato l'esperienza di ricerca di lavoro. Domani vedremo come
  345. dare maggiore possibilità di inserimento a chi pubblica offerte di lavoro
  346. fornendo un Web Service.
  347. __ORM__