symfony: an open-source framework for professionals (dutch php conference 2008)

126
Fabien Potencier Stefan Koopmanschap symfony An Open-Source Framework for Professionals

Upload: fabien-potencier

Post on 11-Apr-2017

10.944 views

Category:

Technology


0 download

TRANSCRIPT

Fabien Potencier Stefan Koopmanschap

symfony An Open-Source Framework

for Professionals

Before we begin

How many have already used symfony for a project,

even a very small personal project?

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

symfony • PHP Web framework • Based on

– 10 years of Sensio experience – Existing Open-Source projects

• Built for : – Professional websites – Complex needs – Demanding environments

Framework

Whatever the application, a framework is build to ease

development by providing tools for recurrent and boring tasks.

Maintainability & Evolutivity

Structure & Standardisation

MVC

Model

View

Controller

Internet

Controleur

Vue

2

Modèle

BDD

3

4

5

6

1

Develop Faster & Better

Write less code

More time for edge cases, business rules, …

less code

less complexity

less bugs

more productivity

more time

Each line of code has an initial cost

… and there is a cost to maintain the line

Kent Beck (based on Yourdon and Constantine)

Costinitial = Costdeveloppement + Costtests

Costmaintenance >> Costinitial

Costmaintenance = Costunderstanding + Costchange + Costtests + Costdeployment

symfony

An Open-Source Framework

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. »

An Open-Source Documentation

•  Open-Source documentation –  The book (450 pages - GFDL) –  Askeet Tutorial (250 pages)

•  Translation in 12 langages –  中文 (Chinese)

–  Deutsch –  Español –  Français –  Italiano –  日本語 (Japanese)

–  Polski –  Português –  Russian –  Ukrainian –  Čeština –  Nederlands

A great Community

Mailing-list support / forums / IRC

240 available plugins

300k unique visitors per month on the official website www.symfony-project.org

« Entreprise » Version

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

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

symfony is a set of cohesive but decoupled classes

symfony platform

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

the symfony MVC framework is based on

the symfony platform

Let’s start a Project

The Project • A simple blog system

– Posts – Categories – Authors – Comments

• Requirements – Maintainable – Customizable – Secure

• Use symfony 1.1

List of recent posts

Categories Post information

Excerpt

Sidebar customization

Add a comment

List of comments

Famfamfam icons

YUI stylesheets

homepage

post

http://www.symfony-project.org/get/design.tgz

Project Initialization

Bootstrap a symfony Project

1.  Install symfony

2.  Initialize a new project

3.  Configure the Web Server

4.  Start coding

Installing symfony

Sandbox: Ready-to-run symfony application

PEAR: Install symfony globally on your machine

Subversion: Be free to have several versions around

symfony CLI $ symfony!

Create a new Project

$ mkdir blog!

$ cd blog!

$ symfony generate:project blog!

Create a new Application ./symfony help generate:app!

Create a new secure Application

./symfony generate:app frontend \!

--escaping-strategy=on \!

--csrf-secret=A$ecret!

Project, Application, Module, Action

Which symfony Version?

./symfony -V!

config/ProjectConfiguration.class.php!

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 </Directory>

</VirtualHost>

Web root directory is web/

symfony Assets Used by the default pages and the Web Debug Toolbar

Configure the Web Server to serve symfony assets

Or, create a symlink

<VirtualHost *:80> … Alias /sf /$sf_symfony_data_dir/web/sf <Directory "/$sf_symfony_data_dir/web/sf"> AllowOverride All Allow from All </Directory> </VirtualHost>

$ cd web/

$ ln -sf ../lib/vendor/symfony/data/web/sf sf

Environments

developers customers end users

development environment

staging environment

production environment

cache cache cache

debug debug debug

logs logs

stats stats stats

logs

development environment

staging environment

production environment

Try a 404 dev environment!

prod environment!

Front Controllers dev environment!

prod environment!

environment

environment

Environment Configuration apps/frontend/config/settings.yml!

Web debug toolbar

environment

Web Debug Toolbar

Web debug toolbar

Create a Module for Posts Create a new ‘post’ module in the ‘frontend’

application

$ php symfony generate:module frontend post!

Project, Application, Module, Action

Action and Template Naming /frontend_dev.php/blog/index

// 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 -->

module action

Browse

/frontend_dev.php/post/index!

Create the Blog Homepage

• 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

apps/frontend/modules/post/templates/indexSuccess.php!

/frontend_dev.php/post/index!

Create an Action to show a Post apps/frontend/modules/post/actions/actions.class.php!

/frontend_dev.php/post/show!

• Create an empy executeShow() action • Copy post.html into showSuccess.php • Fix images and css paths

Project, Application, Module, Action

Extract common Code

Homepage specific content

Post page specific content

The Layout

header.php

page content

footer.php

page content

layout.php

include

include

decoration

A layout wraps the template content

The Layout Move the common code from homepage and post to

the layout

apps/frontend/templates/layout.php!

Customize the Sidebar and the Title The title depends on the page

The sidebar depends on the page

Layout with Several "holes"

Main content

Main content

+ =

Layout Template with slots

Rendered Page

Slot1

Slot

2

Slot 1

Slot 2

A slot content depends on the template context

Create Slots for Title and Sidebar apps/frontend/templates/layout.php!

Fill the Slots

apps/frontend/modules/blog/templates/showSuccess.php!

Passing Data from Action to Template

apps/frontend/modules/blog/actions/actions.class.php!

apps/frontend/modules/blog/templates/indexSuccess.php!

Make the Counter dynamic

Database Schema

A post has an author

A post can be in a category

A post can have comments

Propel : The symfony ORM ORM = Object-Relational Mapping Mapping a relational database to an object-oriented

model Database Abstraction

table row, record field, column

class object proterty

Object-Oriented Relational

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 }

Database Schema config/schema.yml!

Build the Model Classes ./symfony propel:build-model!

From Schema to Object Model

$ ./symfony propel:build-model!

lib/ model/ om/ BasePost.php BasePostPeer.php Post.php PostPeer.php

propel: post: id: ~ name: varchar(255)

1 table > 4 classes?

Base and Custom Classes Base classes

Under model/om/, prefixed by Base Generated by Propel Overwritten each time the schema

changes and the model is generated

Never edit these files!

lib/ model/ om/ BasePost.php BasePostPeer.php Post.php PostPeer.php

lib/ model/ om/ BasePost.php BasePostPeer.php Post.php PostPeer.php

Custom classes Under model/, no prefix Inherit from Base classes Never overwritten Put custom methods here Override base methods here

Peer and Object Classes Peer classes

Suffixed by Peer Useful to retrieve a collection of objects Methods return objects Only static methods (::, self)

lib/ model/ om/ BasePost.php BasePostPeer.php Post.php

PostPeer.php

Object classes No suffix Useful to create / inspect / update records Methods return column values Only object methods (->, $this)

lib/ model/ om/ BasePost.php BasePostPeer.php Post.php PostPeer.php

Database Initialization

mysqladmin create dutchconference!

./symfony configure:database mysql://localhost/dutchconference!

Build the SQL queries ./symfony propel:build-sql!

./symfony propel:insert-sql!

Shortcut for all the previous Tasks

./symfony propel:build-all!

Initial Data data/fixtures/01-data.yml!

Define PKs with names

Use names instead of Pks

Dynamic values

Load Data $ ./symfony propel:data-load frontend!

Summary of Code Generation

schema.yml

Object model Base, Custom, Peer and object classes

Relational database Tables, columns, keys, indexes

propel:build-model!

propel:build-sql!propel:insert-sql!

1

2

3

If the Database preexists the Project

schema.yml

Object model Base, Custom, Peer and object classes

Relational database Tables, columns, keys, indexes

propel:build-model!

propel:build-schema!

2

3

1

Generated Methods of Object Classes Getter for columns

$title = $post->getTitle(); $content = $post->getContent(); $createdAt = $post->getCreatedAt();

Some getters have special options $date = $post->getCreatedAt($dateFormat);

Getter by name $title = $post->getByName('title');

CamelCase version of the column name

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

Get the Posts from the Database

What the Model Layer does Action Model Database

PostPeer::doSelect(new Criteria())!

SELECT * FROM post!

Criteria to SQL translation

resultset!Query execution

Array of Post objects!Object hydrating

What the Model Layer does Template Model Database

$post->getTitle()!

String!Looking up internal attribute

Make the Post show Page dynamic

/frontend_dev.php/post/show?id=1!

Make the Post show Page dynamic

Display a 404 error if the post does not exist

Change the Date Format getPublishedAt() first argument accepts the date()

format or the strftime() format

symfony format_date() helper is i18n aware

Helper Groups •  Tag •  URLs •  Assets (images, JavaScript, CSS, …) •  Subtemplate inclusion (slot, partial, component) •  Links •  Form •  Javascript and Ajax •  Text, number, date manipulation •  I18N •  …

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

Links to the Post Page apps/frontend/config/routing.yml!

lib/modełPost.php!

Links to the Post Page

apps/frontend/modules/post/templates/indexSuccess.php!

apps/frontend/modules/post/actions/actions.class.php!

Link to the Homepage

Add the Comments

apps/frontend/modules/post/templates/showSuccess.php!

What the Model Layer does Template Model Database

$post->getComments()!

SELECT * FROM comment!WHERE comment.post_id= ?!

resultset!Query execution!

Array of Comment objects! Object hydrating!

Comment Form

$ ./symfony propel:build-forms!

Base and Custom Classes Base classes

Under form/base/, prefixed by Base Generated by symfony Overwritten when the schema

changes and the forms are generated

Never edit these files!

lib/ form/ base/ BasePostForm.class.php PostForm.class.php

lib/ form/ base/ BasePost.Form.class.php PostForm.class.php

Custom classes Under form/, no prefix Inherit from Base classes Never overwritten Put custom methods here Override base methods here

Create a Comment Form

apps/frontend/modules/post/actions/actions.class.php!

apps/frontend/modules/post/templates/showSuccess.php!

Create a Comment Form

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

Bind The Form to the Post

Customize the Form lib/form/CommentForm.class.php!

Form Life Cycle

Comments

Security: XSS

Security: CSRF

Create the Category Page lib/modełPostPeer.class.php!

apps/frontend/modules/blog/actions/actions.class.php!

Create the Category Page

apps/frontend/config/routing.yml!

apps/frontend/templates/layout.php!

Create a Partial for the List apps/frontend/modules/blog/templates/_list.php!

apps/frontend/modules/blog/templates/listByCategorySuccess.php!

Create a Component

apps/frontend/templates/layout.php!

apps/frontend/modules/post/actions/components.class.php!

apps/frontend/modules/post/templates/_categories.php!

Create a Web Service for Posts

apps/frontend/config/routing.yml!

apps/frontend/modules/post/templates/indexSuccess.xml.php!

If we have time… • Functional Tests

• Cache

• CRUD to manage posts

Sensio S.A. 26, rue Salomon de Rothschild

92 286 Suresnes Cedex FRANCE

Tél. : +33 1 40 99 80 80

Contact Fabien Potencier

[email protected]

http://www.sensiolabs.com/ http://www.symfony-project.com/