skillswap symfony application build log ======================================= (*) Symfony is installed symfony -V (*) cd in to codebase folder (*) init the 'project' symfony init-project skillswap (*) init the 'applications' symfony init-app frontend symfony init-app backend (*) set-up the virtual host, and add to hosts/dns, check it resolves, should get the 'success' page --->8--- ServerName skillswap.bealers DocumentRoot "/home/bealers/www/S/skillswap/codebase/web" DirectoryIndex index.php php_flag magic_quotes_gpc off php_flag register_globals off Alias /sf /usr/share/php/data/symfony/web/sf AllowOverride All Allow from All LogFormat "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"" TransferLog /var/log/apache/skillswap-access.log ErrorLog /var/log/apache/skillswap-error.log --->8--- The model ============= (*) schema.yml, copy from desktop into PHPed and save out to config drop database skillswap; create database skillswap; grant all on skillswap.* to skillswap@localhost identified by 'skillswap'; (*) Set the connection params in propel.ini (command line) and databases.yml (application) skillswap:skillswap (*) create the mysql db and set the user/password combo (*) build everything symfony propel-build-sql symfony propel-build-all (*) add some content from sql script in ../sql mysql -u root skillswap < ../sql/skillswap-data.sql Admin screens ============= (*) create some admin screens for the 'backend' application symfony propel-init-admin backend content Content symfony propel-init-admin backend user User symfony propel-init-admin backend news News (*) visit the backend http://skillswap.bealers/backend.php/user (*) We might get an error here: try in dev mode so we can figure out what it is http://skillswap.bealers/backend_dev.php/user (*) we now need to: make whole thing authenticated create app//config/security.yml containing ---8<--- all: is_secure: on ---8<--- (*) repeat for the other modules, content and news (*) go to http://skillswap.bealers/backend_dev.php/user and be locked out. very simple security ==================== symfony init-module backend security 1) do login form, the index action tempalte for the security module ---8<---

Authentication

hasErrors()) { ?>Identification failed - please try againget('login')); ?> --->8--- 2) for the app,specify the deault security module and action: apps/backend/config/settings.yml ---8<--- all: .actions: login_module: security login_action: index secure_module: security secure_action: index --->8--- 3) comment out anything in the index action action 4) Notice the login action mentioned in the form? Let's put something in it. apps/backend/modules/security/action.class.php --->8--- public function executeLogin() { if ($this->getRequestParameter('login') == 'admin' && $this->getRequestParameter('password') == 'password') { $this->getUser()->setAuthenticated(true); return $this->redirect('user/index'); } else { $this->getRequest()->setError('login', 'incorrect entry'); return $this->forward('security', 'index'); } } public function executeLogout() { $this->getUser()->setAuthenticated(false); return $this->forward('security', 'index'); } ---8<--- 6) YES THIS IS LAME one could easily add decent security down to the level of individual actions, and of course do lookups on actual users or add credentials. Plus there's sfGuard (which builds on this further) 7) go to http://skillswap.bealers/backend_dev.php/user and login then try go to http://skillswap.bealers/backend_dev.php/content go to http://skillswap.bealers/backend_dev.php/news quick comment about the screen, for example the homepage checkbox on news and the date picker filed types chosen due to data-type, we'll come back to this in a bit Skin the application ==================== (*) navigate to backend/templates/layout.php (*) replace the php output bit with the following top: ---8<---

Symfony Skillswap

getRaw('sf_content') ?>
---8<--- (*) Add the stylesheet ###### ON DESKTOP (*) edit backend/config/view.yml to add the stylesheet reference tidy up the admin screens ========================= (*) To save time we'll only play with one, content (*) edit backend/content/config/generator.yml list: title: List of all content display: [=title] edit: fields: body: { params: rich=true tinymce_options=height:350 } (*) view a content item **BREAKS** (*) Install tiny_mce by copying the tiny_mce folder from src to the web/js folder add validation to user screen ============================== (*) do the __toString() thing first (*) user/validate/edit.yml ------8<------ fields: user{name}: required: msg: You must provide a Username user{email}: required: msg: You must provide an email address sfEmailValidator: email_error: This email address is invalid ------8<------ (*) Don't bother with the other two modules. Build a front-end ========================================================================================= (*) Two modules content and news symfony init-module frontend content Content symfony init-module frontend news News (*) see new stuff under apps/frontend (*) navigate to http://skillswap.bealers/frontend_dev.php/content (*) copy backend template to frontend and edit links so they read:
  • (*) drag in main.css to editor and overwrite original (*) change the routing so ------8<------ # default rules homepage: url: / param: { module: content, action: index } #we'll use this in a bit page: url: /page/:title param: { module: content, action: permalink } ------8<------ (*) this makes frontend_dev now show the index action Sort out content URLs ====================== In the MODEL for content: -----------8<--------------- /** get this content item's title and make it URL friendly */ public function getStrippedTitle() { $result = strtolower($this->getTitle()); // strip all non word chars $result = preg_replace('/\W/', ' ', $result); // replace all white space sections with a dash $result = preg_replace('/\ +/', '-', $result); // trim dashes $result = preg_replace('/\-$/', '', $result); $result = preg_replace('/^\-/', '', $result); return $result; } -----------8<--------------- in the CONTROLLER for content -----------8<--------------- public function executeIndex() { $id = $this->getRequestParameter('id'); //yuck if ($id == "") $id = 1; $this->content = ContentPeer::retrieveByPK($id); $this->forward404Unless($this->content); } // This method grabs the request parameter and compares with those in the DB public function executePermalink() { $contentItems = ContentPeer::doSelect(new Criteria()); $title = $this->getRequestParameter('title'); foreach ($contentItems as $content) { if ($content->getStrippedTitle() == $title) { break; } } $this->forward404Unless($content); $this->getRequest()->setParameter('id', $content->getId()); $this->forward('content', 'index'); } -----------8<--------------- (*) template for content: --------------------------

    getTitle(); ?>

    getBody(); ?> --------------------------- (*) News in the index action: -----------8<--------------- public function executeIndex() { /* select * from news order by published desc*/ $c = new Criteria(); $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED); $this->newsItems = NewsPeer::doSelect($c); } -----------8<--------------- (*) in the template -----------8<--------------- $news)); } ?> -----------8<--------------- (*) in the partial (note the magic with the _ at the front of _newsListItem.php) -----------8<---------------

    getTitle(), 'news/' . $news->getId()); ?>
    getBody(),0,200) . " ... " . link_to("More >", 'news/' . $news->getId());?>


    -----------8<--------------- (*) change the routing for news, makes the URL a bit nicer ----------8<---------------- detail: url: /news/:id param: { module: news, action: detail } ----------8<---------------- (*) create the detail action ----------8<---------------- public function executeDetail() { $this->news = NewsPeer::retrieveByPK($this->getRequestParameter('id')); $this->forward404Unless($this->news); } ----------8<---------------- (*) save out the indexSuccess as detailSucess and change so it reads: ----------------------------

    getTitle(); ?>

    getBody();?>

    -------------------------- Slots, Ajax and Transitions ======================================= (*) I'll do this bit all in one go ans explain what I've done afterwards 1) add the slot to the layout file ----------8<----------------
    ----------8<---------------- (*) change the #content in css file to be 50% width 2) Over-ride the slot on indexSuccess template ----------8<---------------- getBody(); // override the newList slot slot('news'); print "

    Latest news

    "; print "
      "; foreach ($newsList as $news) { print "
    1. " . link_to($news->getTitle(), 'news/' . $news->getId()) . "
    2. "; } print "
    "; print "

    " . link_to_remote('Re-order', array( 'update' => 'newNewsList', 'url' => '/ajax', 'before' => visual_effect('fade','newsList'), 'complete' => visual_effect('appear','newNewsList',array("delay" => "1")) )) . "

    "; end_slot(); ?> ----------8<---------------- [Note the /ajax url] 3) add this to the indexAction to grab the news items: $c = new Criteria(); $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED); $this->doNews($c); ----------8<---------------- also add to the same controller ----------------8<------------ // this should really be in a tools class, but it's another file to open public function doNews($c) { $c->add(NewsPeer::HOMEPAGE, 1); $this->newsList = NewsPeer::doSelect($c); } //action used by the call_to_remote public function executeAjax() { //all we want to do is change the order of the news $c = new Criteria(); $c->addAscendingOrderByColumn(NewsPeer::PUBLISHED); $this->doNews($c); } ------------------------------- 4) add a new ajaxSuccess file, saving out indexSuccess soit looks liek: -------------------------- Latest news

    "; print "
      "; foreach ($newsList as $news) { print "
    1. " . link_to($news->getTitle(), 'news/' . $news->getId()) . "
    2. "; } print "
    "; ?> --------------------------------- 5) change the routing, add: ----------8<---------------- ajax: url: /ajax param: { module: content, action: ajax } ----------8<---------------- That's it Deploy, IF TIME ================ (*) Edit config/properties.ini, adding: ----------8<---------------- [production] host=skillswap.siftware.co.uk port=22 user=www-data dir=/var/www/skillswap.siftware.co.uk ----------8<---------------- (*) show that the app is initially configured but no code: http://skillswap.siftware.co.uk (*) Deploy: symfony sync production go