One hour applicationwith symfony
1vendredi 13 novembre 2009
Aim
• Present symfony in an original way
• Make an application in one hour
2vendredi 13 novembre 2009
Who am I?
•Philippe Gamache
•PHP security expert at Parler Haut, Interagir Librement
•Author of the book « Sécurité PHP 5 et MySQL » with Damien Seguy, at Eyrolles
•http://www.ph-il.ca•http://www.phportail.net•http://lapageamelkor.org•naheulbeukauquebec.ca
3vendredi 13 novembre 2009
Questions? Please wait at the
end, we don’t have much time ?
4vendredi 13 novembre 2009
The application
• Blog
• Comments
• Clean URLs
5vendredi 13 novembre 2009
Install symfony
• Source
• Sandbox
• PEAR
• SVN
• Linux Package (Debian and SUSE)
http://www.symfony-project.org/installation
6vendredi 13 novembre 2009
Install using PEAR
pear channel-discover pear.symfony-project.com
pear install symfony/symfony-1.2.4
7vendredi 13 novembre 2009
Create the project
• Create directory project
• Check symfony’s version
• Create project
$ mkdir -p blog$ cd blog
$ symfony -V
$ symfony generate:project blog
8vendredi 13 novembre 2009
Create the project
• Create an application
• Adjust your web server
$ symfony generate:app / --escaping-strategy=on / --csrf-secret=Unique$ecr3t1 / frontend
9vendredi 13 novembre 2009
http://blog.local/frontend_dev.php/
10vendredi 13 novembre 2009
Activating sfDoctrine
// config/ProjectConfiguration.class.phppublic function setup(){ $this->enableAllPluginsExcept( array('sfPropelPlugin', 'sfCompat10Plugin'));}
11vendredi 13 novembre 2009
The database
• Creating the database
• Configure the project
• Clear Propel connection
$ symfony configure:database / --name=doctrine / --class=sfDoctrineDatabase / "mysql:host=localhost;dbname=blog" / root mYsEcret
$ mysqladmin -uroot -pmYsEcret / create blog
12vendredi 13 novembre 2009
Plugins
• Installing plugins
• sfDoctrineGuardPluginhttp://www.symfony-project.org/plugins/
$ symfony plugin:install / sfDoctrineGuardPlugin / --release=3.0.0
13vendredi 13 novembre 2009
The database diagram
14vendredi 13 novembre 2009
The databade model# config/doctrine/schema.ymlactAs: [Timestampable]
BlogPost: actAs: Timestampable: ~ Sluggable: fields: [title] unique: true columns: is_published: type: boolean default: false allow_comments: type: boolean default: true author_id: integer(4) title: type: string(255) notnull: true content: type: string(500000) notnull: true published_at: date
relations: Author: class: sfGuardUser local: author_id foreign: id type: one BlogComment: columns: blog_post_id: integer author_name: type: string(255) notnull: true author_email: string(255) author_url: string(255) content: type: string(5000) notnull: true relations: BlogPost: local: blog_post_id foreign: id type: one foreignAlias: Comments
15vendredi 13 novembre 2009
Database fixtures# data/fixtures/fixtures.ymlsfGuardUser: philippeg: username: Philippe Gamache password: password is_super_admin: true
sfGuardPermission: sgp_admin: name: admin description: Administrator permission
sfGuardGroup: sgg_admin: name: admin description: Administrator group
sfGuardGroupPermission: sggp_admin: sfGuardGroup: sgg_admin sfGuardPermission: sgp_admin
sfGuardUserGroup: sgug_admin: sfGuardGroup: sgg_admin sfGuardUser: philippeg
16vendredi 13 novembre 2009
Database fixturesBlogPost: post_1: Author: philippeg title: Lorem ipsum dolor sit amet content: | <p>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut...</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do...</p> is_published: true published_at: 09-01-07 post_2: Author: philippeg title: Ut enim ad minim veniam content: | <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p> <p>Duis aute irure dolor in reprehenderit in voluptate velit esse...</p> is_published: true published_at: 09-01-07 post_3: Author: philippeg title: Duis aute irure dolor in reprehenderit in voluptate content: | <p>Duis aute irure dolor in reprehenderit in voluptate velit esse...</p> <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...</p> is_published: true published_at: 09-01-07...
17vendredi 13 novembre 2009
Database fixturesBlogComment: comment_1: BlogPost: post_1 author_name: lorem content: Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. comment_2: BlogPost: post_1 author_name: elit content: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. comment_3: BlogPost: post_3 author_name: aute content: Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. comment_4: BlogPost: post_3 author_name: aute content: ESunt in culpa qui officia deserunt mollit anim id est laborum.
18vendredi 13 novembre 2009
Create the tables
• Create the tables and load all fixtures$ symfony doctrine:build-all-load
19vendredi 13 novembre 2009
Creating the code
• Use the code generator
• Delete unnecessary actions
• executeNew()• executeEdit()• executeUpdate()• executeDelete()• processForm()
$ symfony doctrine:generate-crud / --with-show frontend post BlogPost
20vendredi 13 novembre 2009
Creating the code
• Delete unnecessary files
• templates/_form.php• templates/editSuccess.php• templates/newSuccess.php
• Clear links to other functions
21vendredi 13 novembre 2009
Creating the code
• Edit templates/indexSuccess.php<?php foreach ($blog_post_list as $blog_post): ?> <h2><?php echo link_to($blog_post->gettitle(), '@post_show?slug=' . $blog_post->getslug()) ?></h2> <div>By <?php echo $blog_post->getAuthor() ?> on <?php echo $blog_post->getpublished_at() ?></div> <p> <?php echo $blog_post->getContentSuccess() ?> </p> <p><?php echo link_to('Show more...', '@post_show?slug=' . $blog_post->getslug()) ?></p> <br /><br /><?php endforeach; ?>
22vendredi 13 novembre 2009
Creating the code
• Edit templates/showSuccess.php<h2><?php echo $blog_post->gettitle() ?></h2><div>By <?php echo $blog_post->getAuthor() ?> on <?php echo $blog_post->getpublished_at() ?></div>
<p><?php echo nl2br($blog_post->getcontent()) ?></p>
<hr /><br /><br />
<?php echo link_to('List', '@homepage') ?>
23vendredi 13 novembre 2009
Creating the code
• Add to templates/layout.php
• Modify web/css/main.css with blog.css
<div id="header"> <h1><?php echo link_to('My blog', '@homepage') ?></h1></div>
<div id="content"> <?php echo $sf_data->getRaw('sf_content') ?></div><div id="footer"></div>
24vendredi 13 novembre 2009
Creating the code
• Edit actions.class.php public function executeIndex(sfWebRequest $request) { $this->blog_post_list = Doctrine::getTable('BlogPost') ->createQuery('a') ->where('a.is_published = 1') ->execute(); }
public function executeShow(sfWebRequest $request) { $this->blog_post = Doctrine::getTable('BlogPost') ->findOneBySlug($request->getParameter('slug')); $this->forward404Unless($this->blog_post); }
25vendredi 13 novembre 2009
Creating the code
• Edit BlogPost.class.php
• Modify to routing.yml
public function getContentSummary() { $out = explode('<', nl2br(substr($this->getcontent(), 0, 500))); return $out[0] . '...'; }
homepage: url: / param: { module: post, action: index }
post_show: url: /:slug param: { module: post, action: show }
26vendredi 13 novembre 2009
Add comments
• Use the code generator
• Copy the code you’ll need
$ symfony doctrine:generate-crud / frontend comment BlogComment
27vendredi 13 novembre 2009
Add comments
• Edit code in actions.class.php public function executeIndex(sfWebRequest $request) { $this->blog_post_list = Doctrine::getTable('BlogPost') ->createQuery('p') ->groupBy('p.published_at, p.id') ->where('p.is_published = 1') ->execute(); }
public function executeShow(sfWebRequest $request) { $this->blog_post = Doctrine::getTable('BlogPost') ->findOneBySlug($request->getParameter('slug')); $this->forward404Unless($this->blog_post);
$this->form = new BlogCommentForm(); }
28vendredi 13 novembre 2009
Add comments
• Add the code in actions.class.php public function executeCreate(sfWebRequest $request) { $this->forward404Unless($request->isMethod('post')); $this->blog_post = Doctrine::getTable('BlogPost') ->findOneBySlug($request->getParameter('slug')); $this->forward404Unless($this->blog_post);
$comment = new BlogComment(); $comment->setBlogPost($this->blog_post);
$this->form = new BlogCommentForm($comment); $this->processForm($request, $this->form);
$this->setTemplate('show'); }
29vendredi 13 novembre 2009
Add comments
• Add the code in actions.class.php
• Add to routing.yml
public function processForm(sfWebRequest $request, sfForm $form) { $form->bind($request->getParameter($form->getName())); if ($form->isValid()) { $blog_comment = $form->save(); $this->redirect('@post_show?slug=' . $request->getParameter('slug')); } }
comment: url: /comment/:slug param: { module: post, action: create }
30vendredi 13 novembre 2009
Add comments
• Edit templates/showSuccess.php...<p><?php echo nl2br($blog_post->getcontent()) ?></p><?php if (count($blog_post->getComments())): ?> <ul id="comments"> <?php foreach ($blog_post->getComments() as $comment): ?> <li class="comments"> <br /> <div class="bold">Posted on <?php echo $comment->getcreated_at() ?> by <?php echo $comment->getauthor_name() ?> </div> <p> <?php echo $comment->getcontent() ?> </p> </li> <?php endforeach; ?> </ul><?php endif ?><br />...
31vendredi 13 novembre 2009
Add comments
• Edit templates/showSuccess.php...
<p class="bold">Add your comment</p><br /><?php include_partial('form', array('form' => $form, 'blog_post' => $blog_post)) ?><hr /><br /><br />
<?php echo link_to('List', '@homepage') ?>
32vendredi 13 novembre 2009
Add comments
• Edit templates/indexSuccess.php
• Move _form.php
... <p> <?php echo $blog_post->getContentSummary() ?> </p> <p>Comments (<?php echo count($blog_post->getComments()) ?>) : <?php echo link_to('Show more', '@post_show?slug=' . $blog_post->getslug()) ?></p> <br /><br /><?php endforeach; ?>
33vendredi 13 novembre 2009
Add comments
• Edit templates/_form.php
• Keep only• author_name• author_email• author_url• content
...<form action="<?php echo url_for('@comment?slug=' . $blog_post->getSlug()) ?>" method="POST"><?php if (!$form->getObject()->isNew()): ?><input type="hidden" name="sf_method" value="PUT" /><?php endif; ?> <table>...
34vendredi 13 novembre 2009
Add comments
• Edit BlogCommentForm.class.php public function configure() { unset( $this['created_at'], $this['updated_at'], $this['blog_post_id'] ); $this->validatorSchema['author_email'] = new sfValidatorEmail(array('required' => false)); $this->validatorSchema['author_url'] = new sfValidatorUrl(array('required' => false)); $this->widgetSchema->setLabels(array( 'author_email' => 'Your email ', 'author_name' => 'Your name ', 'author_url' => 'Web site ', 'content' => 'Comment ', )); }
35vendredi 13 novembre 2009
Backend creation
• Create an application$ symfony generate:app / --escaping-strategy=on / --csrf-secret=UniqueSecret / backend
36vendredi 13 novembre 2009
Backend creation
• Create modules$ symfony doctrine:generate-admin / --module=post backend BlogPost$ symfony doctrine:generate-admin / --module=comment backend / BlogComment
37vendredi 13 novembre 2009
Backend creation
• Edit routing.ymlsf_guard_signin: url: /login param: { module: sfGuardAuth, action: signin }
sf_guard_signout: url: /logout param: { module: sfGuardAuth, action: signout }
sf_guard_password: url: /request_password param: { module: sfGuardAuth, action: password }
# default ruleshomepage: url: / param: { module: post, action: index }
38vendredi 13 novembre 2009
Backend creation
• Add to templates/layout.php
• Edit apps/frontend/config/view.yml
<div id="header"> <h1><?php echo link_to('My blog', '@homepage') ?></h1></div>
<div id="menu"> <ul> <li><?php echo link_to('Posts', '@blog_post_post') ?></li> <li><?php echo link_to('Comments', '@blog_comment_comment') ?></li> </ul></div>
<div id="content"> <?php echo $sf_data->getRaw('sf_content') ?></div>
<div id="footer"></div>
39vendredi 13 novembre 2009
Backend creation
• Edit setting.yml
• Edit security.yml
...all: .actions: login_module: sfGuardAuth login_action: signin
secure_module: sfGuardAuth secure_action: secure .settings: enabled_modules: [default, sfGuardAuth]...
default: is_secure: on
40vendredi 13 novembre 2009
Backend creation
• Edit post generator.yml... config: actions: ~ fields: ~ list: title: Message list display: [is_published, author_id, =title, published_at] filter: display: [is_published] form: ~ edit: title: Edit post : "%%title%%" display: [is_published, author_id, title, content, published_at] new: title: New post display: [is_published, author_id, title, content, published_at]
41vendredi 13 novembre 2009
Backend creation
• Edit comment generator.yml... config: actions: ~ _delete: ~ _list: ~ fields: ContentSummary: label: Comments list: object_actions: _delete: ~ actions: __: ~ title: Comments list display: [blog_post_id, =author_name, =ContentSummary] filter: display: [blog_post_id] form: ~ edit: ~ new: ~
42vendredi 13 novembre 2009
Backend creation
• Edit myUser.class.phpclass myUser extends sfGuardSecurityUser{}
43vendredi 13 novembre 2009
To go further
• Add tags
• Add a mini-calendar
• Display posts per month
• Add search
• Add feeds (RSS, ATOM) via sfFeed2plugins
44vendredi 13 novembre 2009
Questions?
[email protected]@ph-il.ca
http://www.symfoy-project.orghttp://www.phportail.net
45vendredi 13 novembre 2009
46vendredi 13 novembre 2009