2. Before we begin
How many have already
used symfony for a project,
even a very small personal project?
3. Who are we?
• Fabien Potencier
– Founder of Sensio
• Web Agency
• Since 1998
• 45 people
• Open-Source Specialists
• Big corporate customers
– Creator and lead developer of symfony
• Stefan Koopmanschap
– Consultant at Ibuildings
– Initiator of symfony-framework.nl and symfonyCamp
– symfony developer for 2 years
4. symfony
• PHP Web framework
• Based on
– 10 years of Sensio experience
– Existing Open-Source projects
• Built for :
– Professional websites
– Complex needs
– Demanding environments
15. Write less code
less code
less complexity
less bugs
more productivity
more time
More time for edge cases, business rules, …
16. Each line of code has an initial cost
Costinitial = Costdeveloppement + Costtests
… and there is a cost to maintain the line
Costmaintenance >> Costinitial
Costmaintenance = Costunderstanding + Costchange + Costtests + Costdeployment
Kent Beck (based on Yourdon and Constantine)
19. MIT Licence
« It is a permissive license, meaning that it permits
reuse within proprietary software on the condition
that the license is distributed with that software. »
26. Version 1.0 released early 2007
– Maintained for 3 years (early 2010)
– ~1 release a month (1.0.16 now)
• Bug and security fixes, compatibility with
new PHP versions fixes
• No new features (even small ones)
• Upgrading is simple and safe
27. Version 1.1 to be released this month
– Maintained for 1 year
– Same release cycle as 1.0
Roadmap
– Version 1.2 Q4 2008
– Version 1.3 Q1 2009
28. symfony is a set of cohesive
but decoupled classes
35. sfEventDispatcher
// sfUser!
$event = new sfEvent($this, ‘user.change_culture’,
array(‘culture’ => $culture));!
$dispatcher->notify($event);!
// sfI18N!
$callback = array($this, ‘listenToChangeCultureEvent’);!
$dispatcher->connect(‘user.change_culture’, $callback);!
• sfI18N and sfUser are decoupled
• « Anybody » can listen to any event
• You can notify existing events or create new ones
54. Configure the Web Server
<VirtualHost *:80>
ServerName myapp.example.com
DocumentRoot "/path/to/blog/web"
DirectoryIndex index.php
<Directory "/path/to/blog/web">
AllowOverride All
Allow from All Web root directory is web/
</Directory>
</VirtualHost>
55. symfony Assets
Used by the default pages and the Web Debug Toolbar
Configure the Web Server to serve symfony assets
<VirtualHost *:80>
…
Alias /sf /$sf_symfony_data_dir/web/sf
<Directory "/$sf_symfony_data_dir/web/sf">
AllowOverride All
Allow from All
</Directory>
</VirtualHost>
Or, create a symlink
$ cd web/
$ ln -sf ../lib/vendor/symfony/data/web/sf sf
65. Action and Template Naming
/frontend_dev.php/blog/index
module action
// in apps/frontend/modules/blog/actions/actions.class.php
<?php
class blogActions extends sfActions
{
public function executeIndex()
{
// do things
}
}
// in apps/frontend/modules/blog/templates/indexSuccess.php
<!–- do things -->
67. Create the Blog Homepage
apps/frontend/modules/post/templates/indexSuccess.php!
• Copy homepage.html into indexSuccess.php
• Copy the images/ and css/ under web/
• Add the base.css CSS in view.yml
• Fix images and css paths
/frontend_dev.php/post/index!
68. Create an Action to show a Post
apps/frontend/modules/post/actions/actions.class.php!
• Create an empy executeShow() action
• Copy post.html into showSuccess.php
• Fix images and css paths
/frontend_dev.php/post/show!
71. The Layout
A layout wraps the template content
header.php
page content
include
decoration
page content
include
footer.php
layout.php
72. The Layout
Move the common code from homepage and post to
the layout
apps/frontend/templates/layout.php!
73. Customize the Sidebar and the Title
The title depends on the page
The sidebar depends on the page
74. Layout with Several "holes"
A slot content depends on the template context
Slot1
Main
content
Slot 2
Main + =
content
Slot 1
Slot 2
Layout Template Rendered
with slots Page
75. Create Slots for Title and Sidebar
apps/frontend/templates/layout.php!
79. Database Schema
A post has an author
A post can be in a category
A post can have comments
80. Propel : The symfony ORM
ORM = Object-Relational Mapping
Mapping a relational database to an object-oriented
model
Database Abstraction
Relational Object-Oriented
table class
row, record object
field, column proterty
81. Schema Conventions
post:
id: # primary key, autoincrement integer
author_id: # foreign key to Author
created_at: # timestamp, set to current time on creation
updated_at: # timestamp, set to current time on update
# column types
published_at: timestamp
title: varchar(255)
content: longvarchar
is_spam: boolean
# complex column definitions
last_name: { type: varchar(100), index: true, required: true }
category_id: { type: integer, foreignTable: category,
foreignReference: id, required: false, onDelete: setnull }
84. From Schema to Object Model
$ ./symfony propel:build-model!
propel: lib/
post: model/
id: ~ om/
name: varchar(255) BasePost.php
BasePostPeer.php
Post.php
PostPeer.php
1 table > 4 classes?
85. Base and Custom Classes
lib/
model/
Base classes
om/ Under model/om/, prefixed by Base
BasePost.php
BasePostPeer.php Generated by Propel
Post.php Overwritten each time the schema
PostPeer.php
changes and the model is
generated
Never edit these files!
lib/ Custom classes
model/
om/ Under model/, no prefix
BasePost.php
Inherit from Base classes
BasePostPeer.php
Post.php Never overwritten
PostPeer.php
Put custom methods here
Override base methods here
86. Peer and Object Classes
lib/ Peer classes
model/
om/ Suffixed by Peer
BasePost.php Useful to retrieve a collection of objects
BasePostPeer.php
Post.php Methods return objects
PostPeer.php Only static methods (::, self)
lib/ Object classes
model/
om/
No suffix
BasePost.php Useful to create / inspect / update
BasePostPeer.php records
Post.php Methods return column values
PostPeer.php Only object methods (->, $this)
92. Summary of Code Generation
2 Object model
propel:build-model! Base, Custom,
Peer and object classes
1
schema.yml
3 propel:build-sql!
propel:insert-sql!
Relational database
Tables, columns, keys, indexes
93. If the Database preexists the Project
3 Object model
propel:build-model! Base, Custom,
Peer and object classes
2
schema.yml
1
propel:build-schema!
Relational database
Tables, columns, keys, indexes
94. Generated Methods of Object Classes
Getter for columns
$title = $post->getTitle(); CamelCase version
$content = $post->getContent(); of the column name
$createdAt = $post->getCreatedAt();
Some getters have special options
$date = $post->getCreatedAt($dateFormat);
Getter by name
$title = $post->getByName('title');
95. Generated Methods of Object Classes
Manipulate primary keys
$commentId = $comment->getId();
// for composite keys, prefer
$commentId = $comment->getPrimaryKey();
Manipulate foreign keys
$postId = $comment->getPostId();
// in practice, these methods are not used much
// use getter for foreign objects instead
$post = $comment->getPost(); // Post object
// as the result is an object, you can chain method calls
$content = $comment->getPost()->getContent();
One-to-Many smart getters
$comments = $post->getCommments(); // Array of Comments
$nb = $post->countCommments(); // Integer
97. What the Model Layer does
Action Model Database
PostPeer::doSelect(new Criteria())!
Criteria to SQL translation
SELECT * FROM post!
Query execution
resultset!
Object hydrating
Array of Post objects!
98. What the Model Layer does
Template Model Database
$post->getTitle()!
Looking up internal attribute
String!
99. Make the Post show Page dynamic
/frontend_dev.php/post/show?id=1!
100. Make the Post show Page dynamic
Display a 404 error if the post does not exist
101. Change the Date Format
getPublishedAt() first argument accepts the date()
format or the strftime() format
symfony format_date() helper is i18n aware
102. Helper Groups
• Tag
• URLs
• Assets (images, JavaScript, CSS, …)
• Subtemplate inclusion (slot, partial, component)
• Links
• Form
• Javascript and Ajax
• Text, number, date manipulation
• I18N
• …
103. Permalinks
• Many applications provide an alternative to
functional URLs
• Permalinks look like links to permanent content
while the resource they reference is dynamically
generated
• Primarily focused at search engines, permalink
often carry more readable data for end users
http://www.symfony-project.org/blog/2008/05/21/new-symfony-security-policy
104. Links to the Post Page
apps/frontend/config/routing.yml!
lib/modełPost.php!
105. Links to the Post Page
apps/frontend/modules/post/templates/indexSuccess.php!
apps/frontend/modules/post/actions/actions.class.php!
108. What the Model Layer does
Template Model Database
$post->getComments()!
SELECT * FROM comment!
WHERE comment.post_id= ?!
Query execution!
resultset!
Array of Comment objects!
Object hydrating!
110. Base and Custom Classes
lib/ Base classes
form/
base/
Under form/base/, prefixed by Base
BasePostForm.class.php Generated by symfony
PostForm.class.php
Overwritten when the schema
changes and the forms are
generated
Never edit these files!
lib/ Custom classes
form/
base/ Under form/, no prefix
BasePost.Form.class.php
Inherit from Base classes
PostForm.class.php
Never overwritten
Put custom methods here
Override base methods here
111. Create a Comment Form
apps/frontend/modules/post/actions/actions.class.php!
apps/frontend/modules/post/templates/showSuccess.php!
113. Propel Forms
• Generated by propel:build-forms
• 1 table = 1 form
• Model introspection to determine
– The widget
– The validation rules
• Automatically converts a form to a Propel object
and save it to the database
• Extensible