One hour application with symfony 1 Wednesday, March 4, 2009
One hour applicationwith symfony
1Wednesday, March 4, 2009
Aim
• Present symfony in an original way
• Make an application in one hour
2Wednesday, March 4, 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
3Wednesday, March 4, 2009
Questions? Please wait at the
end, we don’t have much time ?
4Wednesday, March 4, 2009
The application
• Blog
• Comments
• Clean URLs
5Wednesday, March 4, 2009
Install symfony
• Source
• Sandbox
• PEAR
• SVN
• Linux Package (Debian and SUSE)
http://www.symfony-project.org/installation
6Wednesday, March 4, 2009
Install using PEAR
pear channel-discover pear.symfony-project.com
pear install symfony/symfony-1.2.4
7Wednesday, March 4, 2009
Create the project
• Create directory project
• Check symfony’s version
• Create project
$ mkdir -p blog$ cd blog
$ symfony -V
$ symfony generate:project blog
8Wednesday, March 4, 2009
Create the project
• Create an application
• Adjust your web server
$ symfony generate:app / --escaping-strategy=on / --csrf-secret=Unique$ecr3t1 / frontend
9Wednesday, March 4, 2009
http://blog.local/frontend_dev.php/
10Wednesday, March 4, 2009
Activating sfDoctrine
// config/ProjectConfiguration.class.phppublic function setup(){ $this->enableAllPluginsExcept( array('sfPropelPlugin', 'sfCompat10Plugin'));}
11Wednesday, March 4, 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
12Wednesday, March 4, 2009
Plugins
• Installing plugins
• sfDoctrineGuardPluginhttp://www.symfony-project.org/plugins/
$ symfony plugin:install / sfDoctrineGuardPlugin / --release=3.0.0
13Wednesday, March 4, 2009
The database diagram
14Wednesday, March 4, 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
15Wednesday, March 4, 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
16Wednesday, March 4, 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...
17Wednesday, March 4, 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.
18Wednesday, March 4, 2009
Create the tables
• Create the tables and load all fixtures$ symfony doctrine:build-all-load
19Wednesday, March 4, 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
20Wednesday, March 4, 2009
Creating the code
• Delete unnecessary files
• templates/_form.php• templates/editSuccess.php• templates/newSuccess.php
• Clear links to other functions
21Wednesday, March 4, 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; ?>
22Wednesday, March 4, 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') ?>
23Wednesday, March 4, 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>
24Wednesday, March 4, 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); }
25Wednesday, March 4, 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 }
26Wednesday, March 4, 2009
Add comments
• Use the code generator
• Copy the code you’ll need
$ symfony doctrine:generate-crud / frontend comment BlogComment
27Wednesday, March 4, 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(); }
28Wednesday, March 4, 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'); }
29Wednesday, March 4, 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 }
30Wednesday, March 4, 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 />...
31Wednesday, March 4, 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') ?>
32Wednesday, March 4, 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; ?>
33Wednesday, March 4, 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>...
34Wednesday, March 4, 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 ', )); }
35Wednesday, March 4, 2009
Backend creation
• Create an application$ symfony generate:app / --escaping-strategy=on / --csrf-secret=UniqueSecret / backend
36Wednesday, March 4, 2009
Backend creation
• Create modules$ symfony doctrine:generate-admin / --module=post backend BlogPost$ symfony doctrine:generate-admin / --module=comment backend / BlogComment
37Wednesday, March 4, 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 }
38Wednesday, March 4, 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>
39Wednesday, March 4, 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
40Wednesday, March 4, 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]
41Wednesday, March 4, 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: ~
42Wednesday, March 4, 2009
Backend creation
• Edit myUser.class.phpclass myUser extends sfGuardSecurityUser{}
43Wednesday, March 4, 2009
To go further
• Add tags
• Add a mini-calendar
• Display posts per month
• Add search
• Add feeds (RSS, ATOM) via sfFeed2plugins
44Wednesday, March 4, 2009
Questions?
[email protected]@ph-il.ca
http://www.symfoy-project.orghttp://www.phportail.net
45Wednesday, March 4, 2009