Curso Symfony - Clase 2

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    10 Favorites & 1 Group

    Curso Symfony - Clase 2 - Presentation Transcript

    1. Frameworks de desarrollo Symfony Clase 2 Javier Eguíluz javier.eguiluz@gmail.com
    2. Esta obra dispone de una licencia de tipo Creative Commons Reconocimiento‐No comercial‐ Compartir  bajo la misma licencia 3.0  Se prohíbe explícitamente el uso de este material en  actividades de formación comerciales http://creativecommons.org/licenses/by‐nc‐sa/3.0/es/
    3. This work is licensed under a Creative Commons Attribution‐Noncommercial‐Share Alike 3.0  The use of these slides in commercial courses or trainings is explicitly prohibited http://creativecommons.org/licenses/by‐nc‐sa/3.0/es/
    4. Capítulo 6 Profundizando en  el modelo
    5. El objeto Criteria de Propel
    6. apps/frontend/modules/job/actions/actions.class.php class jobActions extends sfActions { public function executeIndex(sfWebRequest $request) { $this‐>listado = JobeetJobPeer::doSelect( new Criteria() ); } }
    7. SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]]
    8. SELECT * FROM JobeetJob WHERE created_at > time() ‐ 86400 * 30
    9. apps/frontend/modules/job/actions/actions.class.php public function executeIndex(sfWebRequest $request) { $criteria = new Criteria(); $criteria‐>add( WHERE JobeetJobPeer::CREATED_AT, condición time() ‐ 86400 * 30, Criteria::GREATER_THAN ); JobeetJobPeer::doSelect($criteria); $this‐>listado = } FROM JobeetJob SELECT *
    10. apps/frontend/modules/job/actions/actions.class.php public function executeIndex(sfWebRequest $request) { $criteria = new Criteria(); $criteria‐>add( JobeetJobPeer::COMPANY, 'Empresa ACME' ); JobeetJobPeer::doSelect($criteria); $this‐>listado = }
    11. Depurando el código  SQL generado
    12. log/frontend_dev.log Dec 6 15:47:12 symfony [debug] {sfPropelLogger} exec: SET NAMES 'utf8‘ Dec 6 15:47:12 symfony [debug] {sfPropelLogger} prepare: SELECT  jobeet_job.ID, jobeet_job.CATEGORY_ID, jobeet_job.TYPE,  jobeet_job.COMPANY, jobeet_job.LOGO, jobeet_job.URL,  jobeet_job.POSITION, jobeet_job.LOCATION, jobeet_job.DESCRIPTION,  jobeet_job.HOW_TO_APPLY, jobeet_job.TOKEN, jobeet_job.IS_PUBLIC,  jobeet_job.CREATED_AT, jobeet_job.UPDATED_AT FROM ''jobeet_job''  WHERE jobeet_job.CREATED_AT>:p1 SQL Injection Dec 6 15:47:12 symfony [debug] {sfPropelLogger} Binding '2008‐11‐06  15:47:12' at position :p1 w/ PDO type PDO::PARAM_STR
    13. Serializando objetos
    14. lib/model/JobeetJob.php class JobeetJob extends BaseJobeetJob { public function save(PropelPDO $con = null) { if ($this‐>isNew() && !$this‐>getExpiresAt()) { $now = $this‐>getCreatedAt() ? $this‐>getCreatedAt('U') : time(); $this‐>setExpiresAt($now + 86400 * 30);  } return parent::save($con); } }
    15. apps/frontend/modules/job/actions/actions.class.php public function executeIndex(sfWebRequest $request) { $criteria = new Criteria(); $criteria‐>add( JobeetJobPeer::CREATED_AT EXPIRES_AT, time(), Criteria::GREATER_THAN ); $this‐>listado = JobeetJobPeer::doSelect( $criteria ); }
    16. Personalizando la  configuración
    17. ¿Dónde está el problema? public function executeIndex(sfWebRequest $request) { $criteria = new Criteria(); $criteria‐>add( JobeetJobPeer::CREATED_AT, mejor como opción  time() ‐ 86400 * 30, de configuración Criteria::GREATER_THAN ); JobeetJobPeer::doSelect($criteria); $this‐>listado = }
    18. apps/frontend/config/app.yml all: dias_activa:  30 sfConfig::get('app_dias_activa')
    19. Refactorización
    20. ¿Dónde está el problema? Controlador (MVC) public function executeIndex(sfWebRequest $request) { $criteria = new Criteria(); $criteria‐>add( JobeetJobPeer::CREATED_AT, Modelo (MVC) time() ‐ 86400 * 30, Criteria::GREATER_THAN ); JobeetJobPeer::doSelect($criteria); $this‐>listado = }
    21. lib/model/JobeetJobPeer.php Modelo class JobeetJobPeer extends BaseJobeetJobPeer { static public function getActiveJobs() { $criteria = new Criteria(); $criteria‐>add( self::EXPIRES_AT, time(), Criteria::GREATER_THAN ); return self::doSelect($criteria); } } apps/frontend/modules/job/actions/actions.class.php Controlador public function executeIndex(sfWebRequest $request) { $this‐>jobeet_job_list = JobeetJobPeer::getActiveJobs(); }
    22. static public function getActiveJobs() { $criteria = new Criteria(); $criteria‐>add( self::EXPIRES_AT, time(), Criteria::GREATER_THAN ); $criteria‐>addDescendingOrderByColumn( self::EXPIRES_AT ORDER BY ___ DESC ); return self::doSelect($criteria); }
    23. Mostrando las  categorías en la  portada
    24. lib/model/JobeetCategoryPeer.php class JobeetCategoryPeer extends BaseJobeetCategoryPeer { static public function getWithJobs() { $criteria = new Criteria(); $criteria‐>addJoin(self::ID, JobeetJobPeer::CATEGORY_ID); $criteria‐>add( JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN ); SELECT DISTINCT $criteria‐>setDistinct(); return self::doSelect($criteria); } }
    25. apps/frontend/modules/job/actions/actions.class.php public function executeIndex(sfWebRequest $request) { $this‐>categories = JobeetCategoryPeer::getWithJobs(); } apps/frontend/modules/job/templates/indexSuccess.php <?php foreach ($categories as $category): ?> ... <h1><?php echo $category ?></h1> ... <?php foreach ($category‐>getActiveJobs() as $i => $job): ?> ... <?php endforeach; ?> ... <?php endforeach; ?> 
    26. Controlador      Vista             Modelo getWithJobs() 1 JobeetCategoryPeer.php getActiveJobs() 3 executeIndex() indexSuccess.php JobeetCategory.php 4 getActiveJobs() 2 $categories JobeetJobPeer.php
    27. Limitando los  resultados
    28. lib/model/JobeetJobPeer.php class JobeetJobPeer extends BaseJobeetJobPeer { static public function getActiveJobs($max = 10) { $criteria = new Criteria(); $criteria‐>add( mejor en un archivo  self::EXPIRES_AT, de configuración time(), Criteria::GREATER_THAN ); $criteria‐>setLimit($max);  return self::doSelect($criteria); } }
    29. apps/frontend/modules/job/templates/indexSuccess.php <?php foreach ($category‐>getActiveJobs( sfConfig::get('app_max_jobs_on_homepage') ) as $i => $job): ?>  apps/frontend/config/app.yml all: active_days:          30 max_jobs_on_homepage: 10
    30. Archivos de datos  dinámicos
    31. data/fixtures/020_jobs.yml JobeetJob: <?php for ($i = 100; $i <= 130; $i++): ?> job_<?php echo $i ?>: category_id: programming company: Company <?php echo $i.\"\\n\" ?> position: Web Developer location: Paris, France description: | Lorem ipsum dolor sit amet, consectetur adipisicing elit. how_to_apply: | Send your resume to lorem.ipsum [at] company_<?php echo $i ?>.sit is_public: true is_activated: true token: job_<?php echo $i.\"\\n\" ?> email: job@example.com <?php endfor; ?>
    32. Restringir el acceso a  una oferta de trabajo
    33. apps/frontend/config/routing.yml job_show_user: url: /job/:company_slug/:location_slug/:id/:position_slug class: sfPropelRoute options: model: JobeetJob type:  object method_for_criteria: doSelectActive param: { module: job, action: show } requirements: id: \\d+ sf_method: [get]
    34. lib/model/JobeetJobPeer.php class JobeetJobPeer extends BaseJobeetJobPeer { static public function doSelectActive(Criteria $criteria) { $criteria‐>add( JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN ); return self::doSelectOne($criteria); } }
    35. Capítulo 7 La página de cada  categoría
    36. La ruta de la  categoría
    37. apps/frontend/config/routing.yml category: url:      /category/:slug class:    sfPropelRoute param:    { module: category, action: show } options:  { model: JobeetCategory, type: object } lib/model/JobeetCategory.php public function getSlug() { return Jobeet::slugify($this‐>getName()); }
    38. El enlace a la página  de cada categoría
    39. apps/frontend/modules/job/templates/indexSuccess.php <h1> <?php echo link_to($category, 'category', $category) ?> </h1> $total = $category‐>countActiveJobs() ‐ sfConfig::get('app_max_jobs_on_homepage') <?php if ($total > 0): ?> ... echo link_to($count, 'category', $category) ... <?php endif; ?>
    40. DRY (Don’t Repeat Yourself) A process philosophy aimed at reducing duplication, particularly in computing. […] When the DRY principle is applied successfully, a modification of  any single element of a system does not change other logically‐ unrelated elements. Additionally, elements that are logically  related all change predictably and uniformly, and are thus kept  in sync.
    41. xxxPeer::doSelect() xxxPeer::doSelectOne() xxxPeer::doSelectRS() xxxPeer::retrieveByPK() xxxPeer::retrieveByPKs() xxxPeer::doCount() xxxPeer::doInsert() xxxPeer::doDelete() xxxPeer::doUpdate()
    42. Creando el módulo  de las categorías
    43. $ ./symfony propel:generate‐module frontend category actions/ templates/ indexSuccess index edit editSuccess show update newSuccess delete new create $ ./symfony generate:module frontend category actions/ templates/ indexSuccess index
    44. nombre slug
    45. Actualizando la base  de datos
    46. config/schema.yml propel: jobeet_category: id:        ~ name: { type: varchar(255), required: true } slug: type: varchar(255) required: true index: unique getSlug()
    47. lib/model/JobeetCategory.php public function setName($name) { parent::setName($name); $this‐>setSlug(Jobeet::slugify($name)); } $ ./symfony propel:build‐all‐load
    48. apps/frontend/modules/category/actions/actions.class.php class categoryActions extends sfActions { public function executeShow(sfWebRequest $request) { $this‐>category = $this‐>getRoute()‐>getObject(); } } apps/frontend/modules/category/templates/showSuccess.php <h1><?php echo $category ?></h1> ... <?php foreach ($category‐>getActiveJobs() as $i => $job): ?> ...
    49. Elementos parciales
    50. elementos parciales “trozos de código de plantilla que se  pueden reutilizar en varias plantillas” Son iguales que las plantillas en todo salvo que  su nombre empieza por un guión bajo (_)
    51. apps/frontend/modules/job/templates/_list.php <table class=\"jobs\"> <?php foreach ($jobs as $i => $job): ?> <tr class=\"<?php echo fmod($i, 2) ? 'even' : 'odd' ?>\"> <td class=\"location\"> <?php echo $job‐>getLocation() ?> </td> <td class=\"position\"> <?php echo link_to($job‐>getPosition(), 'job_show_user', $job) ?> </td> <td class=\"company\"> <?php echo $job‐>getCompany() ?> </td> </tr> <?php endforeach; ?> </table>
    52. apps/frontend/modules/job/templates/indexSuccess.php <?php include_partial( 'job/list', array('jobs' => $category‐>getActiveJobs( sfConfig::get('app_max_jobs_on_homepage') )) ) ?> apps/frontend/modules/job/templates/showSuccess.php <?php include_partial( 'job/list', array('jobs' => $category‐>getActiveJobs()) ) ?> 
    53. Paginación
    54. apps/frontend/modules/category/actions/actions.class.php public function executeShow(sfWebRequest $request) { $this‐>category = $this‐>getRoute()‐>getObject(); $this‐>pager = new sfPropelPager( app.yml 'JobeetJob', sfConfig::get('app_max_jobs_on_category') ); $this‐>pager‐>setCriteria( $this‐>category‐>getActiveJobsCriteria() ); $this‐>pager‐>setPage($request‐>getParameter('page', 1));  $this‐>pager‐>init(); }
    55. getResults() getNbResults() haveToPaginate() getLinks() getPage() getPreviousPage() getNextPage() getLastPage()
    56. Capítulo 8 Pruebas unitarias
    57. test/ unit/ Prueban funciones y  métodos individualmente functional/ Prueban la aplicación en  su conjunto
    58. El framework de  pruebas lime
    59. require_once dirname(__FILE__).'/../bootstrap/unit.php'; $t = new lime_test(1, new lime_output_color()); número de pruebas  esperadas ok($condicion) is($valor1, $valor2) isnt($valor1, $valor2) like($cadena, $expresionRegular) unlike($cadena, $expresionRegular) is_deeply($array1, $array2)
    60. Ejecutando pruebas  unitarias
    61. 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.'); $ ./symfony test:unit Jobeet
    62. Probando el método  slugify()
    63. Sensio Labs sensio‐labs Paris, France paris‐france test/unit/JobeetTest.php require_once dirname(__FILE__).'/../bootstrap/unit.php';  $t = new lime_test(6, new lime_output_color());  $t‐>is(Jobeet::slugify('Sensio'), 'sensio');  $t‐>is(Jobeet::slugify('sensio labs'), 'sensio‐labs');  $t‐>is(Jobeet::slugify('sensio labs'), 'sensio‐labs');  $t‐>is(Jobeet::slugify('paris,france'), 'paris‐france');  $t‐>is(Jobeet::slugify(' sensio'), 'sensio');  $t‐>is(Jobeet::slugify('sensio '), 'sensio');
    64. test/unit/JobeetTest.php require_once dirname(__FILE__).'/../bootstrap/unit.php';  $t = new lime_test(6, new lime_output_color());  $t‐>comment('::slugify()'); $t‐>is(Jobeet::slugify('Sensio'), 'sensio', '::slugify() pasa la cadena de texto a minúsculas'); $t‐>is(Jobeet::slugify('sensio labs'), 'sensio‐labs', '::slugify() sustituye los espacios en blanco por ‐'); ...
    65. Pruebas unitarias  para Propel
    66. $ mysqladmin ‐uroot ‐p create jobeet_test $ symfony configure:database ‐‐env=test \"mysql:host=localhost;dbname=jobeet_test\" root ConTraSenA config/databases.yml
    67. config/databases.yml dev: propel: class: sfPropelDatabase param: classname: DebugPDO test: propel: class: sfPropelDatabase param: classname: DebugPDO dsn:       'mysql:host=localhost;dbname=jobeet_test' all: propel: class: sfPropelDatabase param: dsn:      'mysql:host=localhost;dbname=jobeet' username: root password: null
    68. test/bootstrap/propel.php include(dirname(__FILE__).'/unit.php'); $configuration = ProjectConfiguration::getApplicationConfiguration( 'frontend', 'test', true ); new sfDatabaseManager($configuration); $loader = new sfPropelData(); $loader‐>loadData(sfConfig::get('sf_test_dir').'/fixtures');
    69. test/unit/model/JobeetJobTest.php include(dirname(__FILE__).'/../../bootstrap/propel.php'); $t = new lime_test(1, new lime_output_color()); $t‐>comment('‐>getCompanySlug()'); $job = JobeetJobPeer::doSelectOne(new Criteria()); $t‐>is( $job‐>getCompanySlug(), Jobeet::slugify($job‐>getCompany()), '‐>getCompanySlug() devuelve el slug del nombre de la empresa' );
    70. Conjuntos de  pruebas unitarias
    71. $ ./symfony test:unit
    72. Capítulo 9 Pruebas  funcionales
    73. La clase sfBrowser
    74. sfBrowser servidor web aplicación  aplicación  Symfony Symfony
    75. get() reload() setHttpHeader() post() click() setAuth() call() select() setCookie() back() deselect() removecookie() forward() restart() clearCookie() followRedirect()
    76. $browser = new sfBrowser(); $browser‐> get('/')‐> click('Design')‐> get('/category/programming?page=2')‐> get('/category/programming', array('page' => 2))‐> post('search', array('keywords' => 'php')) ;
    77. La clase  sfTestFunctional
    78. sfBrowser sfTestFunctional response request user
    79. test/functional/frontend/categoryActionsTest.php include(dirname(__FILE__).'/../../bootstrap/functional.php'); $browser = new sfTestFunctional(new sfBrowser()); $browser‐> get('/category/index')‐> with('request')‐>begin()‐> isParameter('module', 'category')‐> isParameter('action', 'index')‐> end()‐> with('response')‐>begin()‐> isStatusCode(200)‐> checkElement('body', '!/This is a temporary page/')‐> end() ;
    80. interfaz fluída ___() ___() ___() ___()
    81. response request isParameter() checkElement() isFormat() isHeader() isMethod() isStatusCode() hasCookie() isRedirected() isCookie()
    82. Ejecutando pruebas  funcionales
    83. $ ./symfony test:functional frontend categoryActions
    84. Datos de prueba
    85. lib/test/JobeetTestFunctional.class.php class JobeetTestFunctional extends sfTestFunctional { public function loadData() { $loader = new sfPropelData(); $loader‐>loadData( sfConfig::get('sf_test_dir').'/fixtures' ); return $this; } }
    86. Conjuntos de  pruebas funcionales
    87. $ ./symfony test:functional frontend
    88. Conjuntos de  pruebas
    89. $ symfony test:unit $ symfony test:functional frontend $ symfony test:functional backend + $ symfony test:functional ...... $ symfony test:all
    90. Capítulo 10 Los formularios
    91. Crear código HTML del formulario 1. Definir reglas de validación para los datos 2. Procesar valores enviados por el usuario 3. Guardar la información en la base de datos 4. Mostrar posibles mensajes de error 5. Volver a mostrar los datos en el formulario 6.
    92. Symfony ya incluye... • Validación (para cada campo) • Widgets (campos del formulario) • Formularios (widgets + validación)
    93. Formularios
    94. 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) ), )); } }
    95. sfWidgetFormChoice sfWidgetFormInputHidden sfWidgetFormChoiceMany sfWidgetFormInputPassword sfWidgetFormDate sfWidgetFormPropelChoice sfWidgetFormDateRange sfWidgetFormPropelChoiceMany sfWidgetFormDateTime sfWidgetFormPropelSelect sfWidgetFormFilterDate sfWidgetFormPropelSelectMany sfWidgetFormFilterInput sfWidgetFormSchema sfWidgetFormI18nDate sfWidgetFormSchemaDecorator sfWidgetFormI18nDateTime sfWidgetFormSchemaForEach sfWidgetFormI18nSelectCountry sfWidgetFormSchemaFormatter sfWidgetFormI18nSelectCurrency sfWidgetFormSelect sfWidgetFormI18nSelectLanguage sfWidgetFormSelectCheckbox sfWidgetFormI18nTime sfWidgetFormSelectMany sfWidgetFormInput sfWidgetFormSelectRadio sfWidgetFormInputCheckbox sfWidgetFormTextarea sfWidgetFormInputFile sfWidgetFormTime sfWidgetFormInputFileEditable
    96. $this‐>mergeForm(new OtroForm()); $this‐>embedForm('name', new OtroForm());
    97. Formularios de  Propel
    98. schema.yml $ ./symfony propel:build‐forms JobeetJobForm JobeetAffiliateForm JobeetCategoryForm lib/form/
    99. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { unset( $this['created_at'], $this['updated_at'], $this['expires_at'], $this['is_activated'] ); } }
    100. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>validatorSchema['email'] =  new sfValidatorEmail();  } }
    101. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>widgetSchema['type'] = new sfWidgetFormChoice(array( 'choices' => JobeetJobPeer::$types, 'expanded' => true, )); } class JobeetJobPeer extends BaseJobeetJobPeer { } static public $types = array( 'full‐time' => 'Full time', 'part‐time' => 'Part time', 'freelance' => 'Freelance', ); // ... }
    102. sfWidgetFormChoice multiple expanded widget false false false true false true true true
    103. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>validatorSchema['type'] =  new sfValidatorChoice(array( 'choices' => array_keys(JobeetJobPeer::$types), )); } }
    104. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>widgetSchema‐>setLabels(array( 'category_id' => 'Category', 'is_public' => 'Public?', 'how_to_apply' => 'How to apply?', )); } }
    105. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>widgetSchema['logo'] =  new sfWidgetFormInputFile(array( 'label' => 'Company logo', )); $this‐>validatorSchema['logo'] =  new sfValidatorFile(array( 'required' => false, 'label' => sfConfig::get('sf_upload_dir').'/jobs', 'mime_types' => 'web_images', )); } }
    106. sfValidatorFile Valida que el archivo subido sea una  1. imagen Cambia el nombre del archivo por un  2. valor único Guarda el archivo en la ruta indicada 3. Actualiza el valor de la columna logo 4.
    107. class JobeetJobForm extends BaseJobeetJobForm { public function configure() { ... $this‐>widgetSchema‐>setHelp( 'is_public', 'Indica si la oferta de trabajo se puede publicar en sitios web de afiliados' ); } }
    108. apps/frontend/modules/job/templates/newSuccess.php <?php use_stylesheet('job.css') ?> <h1>Post a Job</h1> <?php include_partial('form', array('form' => $form)) ?> parcial  _form
    109. apps/frontend/modules/job/templates/_form.php <?php include_stylesheets_for_form($form) ?> <?php include_javascripts_for_form($form) ?> method, enctype <?php echo form_tag_for($form, '@job') ?> <table id=\"job_form\"> <tfoot><tr><td colspan=\"2\"> <input type=\"submit\" value=\"Preview job\" />  </td></tr></tfoot> <tbody> <?php echo $form ?> </tbody> </table> </form>
    110. Widgets Formulario render() renderRow() renderHiddenFields() render() hasErrors() renderLabel() hasGlobalErrors() renderError() getGlobalErrors() renderHelp() renderGlobalErrors()
    111. <?php echo $form ?> <?php foreach ($form as $widget): ?> <?php echo $widget‐>renderRow() ?> <?php endforeach; ?> 
    112. apps/frontend/modules/job/actions/actions.class.php executeNew(sfWebRequest $request) { public function ... } executeCreate(sfWebRequest $request) { public function ... } executeEdit(sfWebRequest $request) { public function ... } executeUpdate(sfWebRequest $request) { public function ... } executeDelete(sfWebRequest $request) { public function ... } processForm(sfWebRequest $request, sfForm $form) protected function {  ... }
    113. apps/frontend/modules/job/actions/actions.class.php public function executeNew(sfWebRequest $request) { $job = new JobeetJob(); $job‐>setType('full‐time'); $this‐>form = new JobeetJobForm($job); }
    114. lib/model/JobeetJob.php public function save(PropelPDO $con = null) { // ... if (!$this‐>getToken()) { $this‐>setToken( sha1($this‐>getEmail().rand(11111, 99999)) ); } return parent::save($con); } lib/form/JobeetJobForm.class.php class JobeetJobForm extends BaseJobeetJobForm { public function configure() { unset( $this['token'] ); } }
    115. apps/frontend/config/routing.yml job: class:        sfPropelRouteCollection options:      { model: JobeetJob, column: token } requirements: { token: \\w+ } http://localhost.jobeet/job/TOKEN/edit
    116. La página de  previsualización
    117. apps/frontend/modules/category/templates/showSuccess.php <?php if($sf_request‐>getParameter('token') == $job‐>getToken()): ?> <?php include_partial('job/admin', array('job' => $job)) ?> <?php endif; ?> apps/frontend/modules/job/templates/_admin.php <h3>Admin</h3> <ul> <?php if (!$job‐>getIsActivated()): ?> <li><?php echo link_to('Edit', 'job_edit', $job) ?></li>  <li><?php echo link_to('Publish', 'job_edit', $job) ?></li> <?php endif; ?> ... <?php if ($job‐>isExpired()): ?> Expired <?php else: ?> Expires in <strong> <?php echo $job‐>getDaysBeforeExpires() ?></strong> days <?php endif; ?> ...
    118. Activando y  publicando las  ofertas
    119. apps/frontend/config/routing.yml job: class:   sfPropelRouteCollection options: model:          JobeetJob column:         token object_actions: { publish: put } requirements: token: \\w+
    120. apps/frontend/modules/job/actions/actions.class.php public function executePublish(sfWebRequest $request) { $request‐>checkCSRFProtection(); $job = $this‐>getRoute()‐>getObject(); $job‐>publish(); $this‐>getUser()‐>setFlash( 'notice', sprintf('Your job is now online for %s days.',  sfConfig::get('app_active_days')) ); $this‐>redirect($this‐>generateUrl('job_show_user', $job)); }
    121. Capítulo 11 Probando los  formularios
    122. Enviando un  formulario
    123. test/functional/frontend/jobActionsTest.php $browser‐>info('3 ‐ Post a Job page')‐> info(' 3.1 ‐ Submit a Job')‐> get('/job/new')‐> with('request')‐>begin()‐> isParameter('module', 'job')‐> isParameter('action', 'new')‐> Preview your job end()‐> click('Preview your job', array('job' => array( 'company' => 'Sensio Labs', 'url' => 'http://www.sensio.com/', 'logo' => sfConfig::get('sf_upload_dir').'/jobs/sensio‐labs.gif',  'position' => 'Developer', 'location' => 'Atlanta, USA', 'is_public' => false, )))‐> with('request')‐>begin()‐> isParameter('module', 'job')‐> isParameter('action', 'create')‐> end()‐> ;
    124. Seguridad
    125. $ symfony generate:app jobeet ‐‐escaping‐strategy=on ‐‐csrf‐secret=secreto frontend XSS &lt;p&gt;Soy un  <p>Soy un usuario  usuario  malvado</p> malvado&lt;/p&gt; y voy a meter JS  y voy a meter JS <script  &lt;script type=\"text/javascript type=&quot;text/javas \">document.write(\"Hol cript&quot;&gt;docume a!\")</script> nt.write(&quot;Hola!& quot;)&lt;/script&gt; 
    126. $ symfony generate:app jobeet ‐‐escaping‐strategy=on ‐‐csrf‐secret=secreto frontend CSRF <form> <input type=\"hidden\"  <form> name=\"_csrf_token\"  <input type=\"text\" .../> value=\"...\" />  <input type=\"text\" .../> <input type=\"text\" .../> ... <input type=\"text\" .../> </form> ... </form>
    127. Tareas de  mantenimiento
    128. $ php lib/vendor/symfony/data/bin/symfony
    129. lib/task/JobeetCleanupTask.class.php class JobeetCleanupTask extends sfBaseTask { protected function configure() { $this‐>addOptions(array( new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED,  'The environement', 'prod'), new sfCommandOption('days', null, sfCommandOption::PARAMETER_REQUIRED,  '', 90), )); $this‐>namespace = 'jobeet'; $this‐>name = 'cleanup'; $this‐>briefDescription = 'Cleanup Jobeet database'; $this‐>detailedDescription = <<<EOF The [jobeet:cleanup|INFO] task cleans up the Jobeet database:  [./symfony  jobeet:cleanup ‐‐env=prod ‐‐days=90|INFO] EOF; } protected function execute($arguments = array(), $options = array()) { $databaseManager = new sfDatabaseManager($this‐>configuration); $nb = JobeetJobPeer::cleanup($options['days']); $this‐>logSection('propel', sprintf('Removed %d stale jobs', $nb)); } }

    + Javier EguiluzJavier Eguiluz, 9 months ago

    custom

    3267 views, 10 favs, 5 embeds more stats

    Presentación de la segunda clase de un curso sobre more

    More info about this document

    CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

    Go to text version

    • Total Views 3267
      • 3049 on SlideShare
      • 218 from embeds
    • Comments 0
    • Favorites 10
    • Downloads 0
    Most viewed embeds
    • 213 views on http://www.symfony.es
    • 2 views on http://static.slideshare.net
    • 1 views on http://feeds.feedburner.com
    • 1 views on http://localhost
    • 1 views on http://www.mefeedia.com

    more

    All embeds
    • 213 views on http://www.symfony.es
    • 2 views on http://static.slideshare.net
    • 1 views on http://feeds.feedburner.com
    • 1 views on http://localhost
    • 1 views on http://www.mefeedia.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories

    Groups / Events