• No results found

Workshop - Day 1. symfony workshop

N/A
N/A
Protected

Academic year: 2021

Share "Workshop - Day 1. symfony workshop"

Copied!
152
0
0

Loading.... (view fulltext now)

Full text

(1)

symfony workshop www.symfony-project.com www.sensiolabs.com

Workshop - Day 1

(2)
(3)

symfony workshop www.symfony-project.com www.sensiolabs.com

Sensio

Web agency

70 people dedicated to webdevelopment

Open-Source specialists

Customers : big corporate companies

Webmarketing TechnologiesInternet

Sensio

Web Agency

Creator of the

symfony

framework

lundi 15 mars 2010

(4)

Symfony

Open-Source PHP 5 Framework

Based on :

11 years of experience

Open-Source projects

Created for :

Professionals

Complex needs

Demanding environments

(5)

symfony workshop www.symfony-project.com www.sensiolabs.com

What is a Framework ?

«

 

Whatever the application, a framework is build

to ease development by providing tools for

recurrent and boring tasks.

 

»

Generic components

Bundled by default

Well integrated

Optimized for the web

Professional Web Developments

(6)

What is a CMS ?

Content Management System

Standard features

Pre-made application

(7)

symfony workshop www.symfony-project.com www.sensiolabs.com

 Don’t reinvent the wheel and use best practices

 Develop faster and better

 Develop evolutive and maintenable applications

 Become the framework for professionals

Main goals of symfony

(8)

Develop better

Kent Beck (based on Yourdon and Constantine)

Each line of code has an initial cost

… and a cost to maintain the line of code

Cost

initial

= Cost

development

+ Cost

tests

Cost

maintenance

>>

Cost

initial

(9)

Develop faster

Write less code

More time for business rules, edge cases, …

Less code

Less complexity

Less bugs

More productivity

More time

symfony workshop www.symfony-project.com www.sensiolabs.com

(10)

Become the framework

for professionals

(11)

Main Advantages

Symfony is about code, but also…

An Open-Source Framework

An Open-Source Documentation

An international community

An “Entreprise” version

symfony workshop www.symfony-project.com www.sensiolabs.com

(12)

An Open-Source Framework

Released under the 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

(13)

An Open-Source Documentation

Several O

ffi

cial Books

The Definitive Guide (450 pages)

Practical symfony (350 pages)

The Reference Guide (150 pages)

More With symfony (320 pages - 5 translations)

Lots of available translations

Free online

symfony workshop www.symfony-project.com www.sensiolabs.com

(14)

A large community

(15)

Dedicated Event : the symfony live

February, 2010, the 15th, 16th and 17th

2 days of conferences

+1 Trainings Day with symfony experts

Symfony and Zend Framework together

Symfony and Webservices

What’s new in symfony 1.3 / 1.4

Hosting practices with symfony

Doctrine 1.2

symfony workshop www.symfony-project.com www.sensiolabs.com

(16)

An «

 

Entreprise

 

» Version

Version 1.4 released in December 2009

~1 release per month

Bugs fixes, security and compatibility issues with newer

versions of PHP

No new feature added

Updating is simple and safe

Migrating is safe

Supported for 3 years

Commercial support

(17)

Entreprise Features

Security

Environments and Deployment support

Unit and functional testing frameworks

Configurable and extensible

Model / View / Controller architecture

Admin Generator

Tools for the developer (debugging, log, queries logging…)

Cache management

Clean and smart URLs

Internationalization (I18N) and localization (L10N)

symfony workshop www.symfony-project.com www.sensiolabs.com

(18)

Security

Protected by

default

against most web attacks

Cross Site Scripting (XSS)

Cross Site Request Forgery (CSRF - « Sea Surf »)

SQL Injection

Why ?

Because XSS attacks are really easy to exploit

(19)

Environments and deployment

Symfony recognized the need for di

ff

erent

environments:

development,

testing,

production

Easy deployments

symfony project:deploy production --go

symfony workshop www.symfony-project.com www.sensiolabs.com

(20)

Unit and Functional Testing

Symfony

automates

functional tests by

simulating a browser

Why ?

Manual tests are not reproducible… Customers

never test their applications

(21)

Configurability and Extensibility

Symfony is

configurable

and easily

extensible

Easy to use plugins system

Why ?

The web evolves quickly

Some customers have specific needs

The framework cannot and must not do everything

Ease external contributions

symfony workshop www.symfony-project.com www.sensiolabs.com

(22)

MVC Architecture

Better concerns separation:

Business rules (Model)

Templates (View)

File structure

Conventions (naming, formats …)

Why ?

(23)

The MVC architecture

Web applications design

3 di

ff

erent layers:

Model: Business logic

View : Presentation

Controller

: Application logic

Advantages:

Better encapsulation

Code is reusable

Robust

controller

view

model

response

client

internet

server

request

lundi 15 mars 2010

(24)

Back-O

ffi

ce

A

utomatic

creation of a backend interface

Records lists

Pagination

Sorting

Why ?

All websites have a backend

Boring to develop

Filters

Validation

(25)

Tools for the developer

Symfony comes with tools to help debugging

Why ?

To improve the developer's productivity

To ease debugging

symfony workshop www.symfony-project.com www.sensiolabs.com

(26)

Cache management

The Symfony cache system is fined-grained

Why ?

(27)

symfony workshop www.symfony-project.com www.sensiolabs.com

Clean URLs

symfony decouples URLs et code

Why?

SEO optimization

They are indexed by search engine, copy/pasted in

emails, bookmarked, …

Masks technical implementation

/blog.php?section=symfony&article_id=18475

/blog/2008-01-30/symfony-happy-new-year

(28)

i18n

Symfony has built-in support

for i18n and l10n

Why?

(29)

symfony workshop www.symfony-project.com www.sensiolabs.com

A professional framework

Based on experience

Stable versions

Maintained with commercial support

Large community

Extensible

Stable API

Open-Source Documentation

Focused on best practices and security

(30)
(31)

symfony workshop www.symfony-project.com www.sensiolabs.com

Before we begin

Copy the

exercises/

folder in your web root folder

Check your configuration

/exercises/check.php

(32)

The exercises/ directory

All exercises for this workshop with solutions

You must do the exercises to learn

(33)

symfony workshop www.symfony-project.com www.sensiolabs.com

The Application

A pure and simple PHP application

Attendees management system

List

Create

Delete

Display

(34)

Install the application

(35)

symfony workshop www.symfony-project.com www.sensiolabs.com

Play with the application

/exercises/attendee/version_0/welcome.php

(36)

Play with the application

(37)

symfony workshop www.symfony-project.com www.sensiolabs.com

Main features of the application

Flat programming

Typical PHP4 application

No class

No abstraction

… and a lot of problems

(38)

Problem n°1: No structure

The structure is not reproducible

Flat structure

Librairies under the main root directory?

An empty index.html file must be created to ensure

that the files are not browseable

Librairies?

inc/

includes/

lib/

(39)

symfony workshop www.symfony-project.com www.sensiolabs.com

Problem n°2: Duplication

Code duplication / lots of includes

/exercises/attendee/version_0/welcome.php

/exercises/attendee/version_0/attendee.php

(40)

Problem n°3: Security

Security is not taken care of:

SQL injection

XSS

CSRF

(41)

symfony workshop www.symfony-project.com www.sensiolabs.com

Problem n°3: Security

SQL injection

(42)

Problem n°3: Security

SQL injection solution

Variable escaping within SQL statements

(43)

symfony workshop www.symfony-project.com www.sensiolabs.com

Problem n°3: Security

XSS - Cross-Site Scripting

(44)

Probleme n°3: Security

XSS solution - Cross-Site Scripting

Escape variables when they are used in a template

(45)

symfony workshop www.symfony-project.com www.sensiolabs.com

Problem n°4: Edge cases

Edge cases are not taken care of:

the application is not robust

What if a user enter an empty name ou a long one?

No data validation

And if the database does not exist?

Errors are displayed right in the browser

(46)

Problem n°5: Not maintainable

HTML and PHP code are mixed up together

Modifying the display is complicated

(47)

symfony workshop www.symfony-project.com www.sensiolabs.com

Probleme n°5: Not maintainable

Lots of hardcoded paths

(48)

Problem n°6: Wheel is reinvented

File structure

Coding standards

Database access

(49)

symfony workshop www.symfony-project.com www.sensiolabs.com

Problem n°7: No documentation

No class

No functions

No PHPDoc

lundi 15 mars 2010

(50)

Problem n°8: No tests

The application is not tested

Testing is about automated tests of course

No class and no function to test

Unit testing is not possible

The application is not testable

How to test the SQL statement that creates an

(51)

symfony workshop www.symfony-project.com www.sensiolabs.com

Common PHP application problems

No structure

Duplication

Security

Edge cases

Maintainance

The wheel is reinvented

No documentation

No test

(52)

Conclusion

The application is:

hard to maintain

hard to make evolve

a pain to develop

(53)

symfony workshop www.symfony-project.com www.sensiolabs.com

How to resolve those problems ?

Use a framework

Use symfony

(54)
(55)

symfony workshop www.symfony-project.com www.sensiolabs.com

4 installation ways

Using SVN

[recommended]

http://svn.symfony-project.com/branches/1.4

Download

sf_sandbox1.4.1.zip

Using PEAR channel

Download symfony1.4.1.zip

$ pear channel-discover pear.symfony-project.org

$ pear install symfony/symfony-1.4.1

(56)

Go fast: the sandbox

A ready-to-use symfony application

A simple archive to uncompress at the root of the server

An application bundled with all the symfony librairies

No need to configure a web server

Project is already bootstrapped

(57)

symfony workshop www.symfony-project.com www.sensiolabs.com

PHP Best Practices

The web root directory only contains static files and

the front controllers

Source control (Subversion / CVS / Git / Mercurial…)

Several developers can work on the same application

Change your code with confidence

Dependency management with

svn:externals

PEAR

Eases the installation and the migration

Knows about dependencies, versions, and stability…

(58)

Symfony project initialization

Just follow the four steps below:

Install symfony

Initialize a new project

Configure the Web server

(59)

symfony workshop www.symfony-project.com www.sensiolabs.com

Step 1: Install symfony

Install symfony with PEAR

For previous versions

$ pear channel-discover pear.symfony-project.com

$ pear install symfony/symfony-1.4

$ pear install symfony/symfony-1.2

(60)

Step 2 : Initialize a new project

apps/

batch/

cache/

config/

ProjectConfiguration.php

data/

doc/

lib/

log/

plugins/

test/

$ mkdir ~/myproject

$ cd ~/myproject

(61)

symfony workshop www.symfony-project.com www.sensiolabs.com

Step 3: Create a new application

Create a new application with the CLI

Get help for a task

$ php symfony generate:app frontend

$ php symfony help generate:app

(62)

Result : initialize an application

apps/

myapp/

config/

i18n/

lib/

modules/

templates/

batch/

cache/

config/

data/

doc/

lib/

log/

plugins/

test/

web/

(63)

symfony workshop www.symfony-project.com www.sensiolabs.com

Step 4: 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>

The web root is web/

(64)

Which symfony version?

The symfony version can be found in

config/

ProjectConfiguration.class.php

… or directly from the command line:

config/

ProjectConfiguration.class

.php

<?php

require_once

'/path/to/symfony/lib/autoload/sfCoreAutoload.class.php';

sfCoreAutoload::register();

(65)

symfony workshop www.symfony-project.com www.sensiolabs.com

Refactor a pure PHP4

application

(66)

Let’s begin the refactoring

Switch to version_1/

With a symfony sandbox

It is a pre-packaged project

(67)

symfony workshop www.symfony-project.com www.sensiolabs.com

Scalability of structure

Application

apps/

[application name]

/

config/

i18n/

lib/

modules/

templates/

layout.php

error.php

error.txt

Module

apps/

[application name]

/

modules/

[module name]

/

actions/

actions.class.php

config/

lib/

templates/

indexSuccess.php

lundi 15 mars 2010

(68)
(69)

The command line interface

Needed in production when the configuration change

Files under

cache/

folder can be removed manually

$ php symfony cache:clear

$ php symfony cc

(70)

The CLI is your best friend

Automates several redundant operations:

Default directory structure and default files

Code generation (model files, backend, …)

Repetitive and complex tasks

Useful to manage the project lifecycle

Initialization, creation

Test

(71)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 1: Module Creation

Create a new

attendee

module in the

frontend

application

$ php symfony generate:module frontend attendee

(72)

Command line tasks

(73)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 2: Copy PHP files

Copy from version_0

in web/css/

main.css

in web/images/

attendee.jpg

in data/

data.db

in apps/frontend/templates/

config.php

header.php

footer.php

Content of welcome.php in indexSuccess.php

(74)

/exercises/attendee/version_1/web/frontend_dev.php/attendee/index

Exercise 3: Navigation & Routing

(75)

// in apps/frontend/modules/attendee/actions/

actions.class.php

<?php

class

attendeeActions

extends

sfActions

{

public function

executeIndex

( sfWebRequest $request )

{

// do things

}

}

symfony workshop www.symfony-project.com www.sensiolabs.com

Action and template names

/exercises/attendee/version_1/web/frontend_dev.php/attendee/index

Module

Action

// in apps/frontend/modules/attendee/templates/

indexSuccess.php

<!–- do things -->

lundi 15 mars 2010

(76)

Exercise 4: The action

Edit

actions.class.php

and

remove the code with

forward in

executeIndex()

See your

attendee/index

We want a list of

(77)

symfony workshop www.symfony-project.com www.sensiolabs.com

Constants vs. variables

Constants are fast but only allow scalar values

Symfony replaces constants with sfConfig

With constants (PHP)

With sfConfig (Symfony)

define('FOO', 'bar');

sfConfig::set('foo', 'bar');

echo FOO;

echo sfConfig::get('foo');

$bool = defined(FOO);

$bool = sfConfig::has('foo');

if (defined(FOO)) {

echo FOO;

} else {

echo 'bar';

}

echo sfConfig::get('foo', 'bar');

No equiv.

sfConfig::set('foo', new Bar());

No equiv.

sfConfig::clear();

(78)

Exercise 5: Fix links

<?php echo image_tag(

'attendee.jpg‘

)?>

Fix the link to the image in

header.php

Use

sfConfig

to read some config variables

Some constants are available

Fix the link to the sqlite database in

config.php

(79)

symfony workshop www.symfony-project.com www.sensiolabs.com

Move some template code to the

action

Content of

config.php

in the

executeIndex()

method

DB closing from

footer.php

to

executeIndex()

Remove the

config.php

file

Remove the

config.php

inclusion

in

indexSuccess.php

Exercise 6: Move the code

We want to list attendees, we need a DB connection

We re-use the original code

(80)

Pass a variable to a template

Pass the

$userName

variable to the template

Setting a virtual property allows to pass the

variable to the corresponding template

(81)

symfony workshop www.symfony-project.com www.sensiolabs.com

Pass a variable to a template

class

attendeeActions

extends

sfActions

{

public function

executeIndex

(

sfWebRequest

$request)

{

$this

->

count

=

10

;

}

}

<p>

Attendees: <?php

echo

$count ?>

</p>

actions.class.php

indexSuccess.php

(82)

Easy to read ?

<h1>My article</h1>

<?php

if

(

$user

->

isAdministrator())

{

echo "

<h2>Administrator links</h2>";

echo link_to('

edit',

'

article/edit?id='.

$

article-

>

getId());

}

(83)

symfony workshop www.symfony-project.com www.sensiolabs.com

Easy to read ?

<h1>My article</h1>

<?php

if

(

$user

->

isAdministrator()): ?>

<h2>Administrator links</h2>

<?php

echo

link_to(

'edit'

,

'article/edit?id='

.

$article

->

getId()) ?>

<?php

endif

; ?>

(84)

Alternative PHP syntax

foreach (

$vars

as

$var

)

{

echo

"

This is ".

$

var.

"<br />";

}

<?php foreach (

$vars

as

$var

): ?>

This is <?php

echo

$var

?><br />

<?php endforeach; ?>

(85)

symfony workshop www.symfony-project.com www.sensiolabs.com

Readability in templates

if (

$condition

) {

echo

'foo'

;

} else {

echo

'bar'

;

}

<?php if (

$condition

): ?>

foo

<?php else: ?>

bar

<?php endif; ?>

lundi 15 mars 2010

(86)

Templating Best Practices

Use the PHP alternative syntax

No business logic must be in actions

KISS (Keep It Simple Stupid)

No more than 1 line of PHP code at a time

Meaningful variable names

(87)

symfony workshop www.symfony-project.com www.sensiolabs.com

The layout solution

header.php

welcome.php

footer.php

welcome.php

layout.php

include

include

decoration

lundi 15 mars 2010

(88)

Reusable template code

Here is the typical way to include a snippet of code:

Not D.R.Y

Not flexible

<?php

$title

=

"My page"

; ?>

<?php

include

'header.php'

; ?>

<?php

include

'footer.php'

; ?>

(89)

symfony workshop www.symfony-project.com www.sensiolabs.com

Layout and Templates

Layout is the main “template”

Layout is optional

AJAX

RSS

Template is the rendering of each action

no code duplication

Local representation of the page

Templates are reusable in di

ff

erent layouts

(90)

Exercise 7: Move the DB code

Move the DB code from the list to the action

query

=

sqlite_query(

$db

,

'

SELECT

count(*)

FROM

attendee'

);

$this

->

count

=

sqlite_fetch_single(

$query

);

$this

->

attendees

=

array();

$query

=

sqlite_query(

$db

,

'

SELECT

*

FROM

attendee'

);

while

(

$attendee

=

sqlite_fetch_array(

$query

, SQLITE_ASSOC))

{

(91)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 7: Move the DB code

<p>

There are <?php

echo

$count

?> attendee(s).

</p>

<table id="list" cellspacing="0">

<tr>

<th>Id</th>

<th>Name</th>

<th>&nbsp;</th>

</tr>

<?php

foreach

(

$attendees

as

$attendee

): ?>

<tr>

<!-- ... -->

</tr>

<?php

endforeach

?>

</table>

lundi 15 mars 2010

(92)

Exercise 8 : Alternative PHP syntax

Refactor the attendees list by using the PHP alternative syntax

A template should contain a lot of HTML, with some PHP

<?php

foreach

(

$attendees

as

$attendee

): ?>

<tr>

<td>

<?php

echo

link_to(

$attendee

['id'], 'attendee/show?id='

.

$attendee

['id']) ?>

</td>

<td><?php

echo

$attendee

['name'] ?></td>

<td>

<?php

echo

link_to('delete', 'attendee/delete?id='

.

$attendee

['id']) ?>

</td>

(93)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 9: Layout

Move the

header

and

footer

code in

layout.php

(94)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd

">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>

<?php include_http_metas() ?>

<?php include_metas() ?>

<?php include_title() ?>

</head>

<body>

<div id="container">

<?php

echo

image_tag(

'attendee.jpg'

,

'height=120 align=right'

) ?>

<h1>

<?php

echo

link_to(

'Attendee Application'

,

'attendee/index'

) ?>

</h1>

<?php

echo

$sf_content

?>

<p class="footer">&copy; Not Sensio</p>

</div>

(95)

symfony workshop www.symfony-project.com www.sensiolabs.com

<h2>Create a new Attendee</h2>

<form action="welcome.php" method="POST">

<label for="name">Name: </label><input size=25 type="text" name="name" />

<input type="hidden" name="action" value="create" />

<input type="submit" value="go" />

</form>

<h2>All Attendees</h2>

<p>

There are <?php

echo

$count

?> attendee(s).

</p>

<table id="list" cellspacing="0">

<tr>

<th>Id</th>

<th>Name</th>

<th>&nbsp;</th>

</tr>

<?php

foreach

(

$attendees

as

$attendee

): ?>

<tr>

<td><?php

echo

link_to(

$attendee

[

'id'

],

'attendee/show?id='

.

$attendee

[

'id'

]) ?></td>

<td><?php

echo

$attendee

[

'name'

] ?></td>

<th><?php

echo

link_to(

'delete'

,

'attendee/delete?id='

.

$attendee

[

'id'

]) ?></th>

</tr>

<?php

endforeach

; ?>

</table>

(96)

Adding features

We need some extra features:

Creating new attendees

Deleting attendees

Showing an attendee

A module contains several actions:

(97)

Adding new features

class

attendeeActions

extends

sfActions

{

public function

executeIndex

(

sfWebRequest

$request

)

{

// ...

}

public function

executeCreate

(

sfWebRequest

$request

) {

}

public function

executeShow

(

sfWebRequest

$request

) {

}

public function

executeDelete

(

sfWebRequest

$request

) {

}

}

Just create new methods in the actions class

(98)

Exercise 10: The create action

Opens a connection on the database

Receives the form submitted parameters

Inserts the submitted values into the DB

Closes the database connection

(99)

symfony workshop www.symfony-project.com www.sensiolabs.com

public function

executeCreate

(

sfWebRequest

$request

)

{

if

(

!

$db

=

sqlite_open

(

sfConfig

::

get(

'sf_data_dir'

)

.

'/data.db'

),

0666

,

$error

)) {

die

(

$error

);

}

if

(

$request

->

isMethod(

'post'

))

{

$name

=

$request

>

getParameter(

'name'

);

$query

=

sqlite_exec

(

$db

,

'

INSERT INTO

attendee (name)

VALUES

(

"'

.

$name

.

'")'

,

$error

);

if

(

!

$query

) {

die

(

"Error in query: '

$error

'"

);

}

}

sqlite_close

(

$db

);

$this

->

redirect(

'attendee/index'

);

}

Exercise 10: The create action

The $request object allows to

retrieve GET or POST data and check

the HTTP method

(100)

Exercise 10: The create action

Finally, change the form action with the

url_for()

helper

<h2>Create a new Attendee</h2>

<form action="<?php

echo

url_for(

'attendee/create'

) ?>" method="POST">

<label for="name">Name: </label><input size=25 type="text" name="name" />

<input type="hidden" name="action" value="create" />

<input type="submit" value="go" />

</form>

(101)

symfony workshop www.symfony-project.com www.sensiolabs.com

Open a connection on the database

Retrieve a record by its id given in URI

Pass the record array to the template

Close the DB connection

Forward the user to a 404 page if no record

Display data in the view

Exercise 11: The show action

(102)

public function

executeShow

(

sfWebRequest

$request

)

{

if

(

!

$db

=

sqlite_open

(

sfConfig

::

get(

'sf_data_dir'

)

.

'/data.db'

),

0666

,

$error

))

{

die

(

$error

);

}

$query

=

sqlite_query

(

$db

,

'

SELECT

*

FROM

attendee

WHERE

id =

'

.

$request

->

getParameter(

'id'

)

);

$this

->

attendee

=

sqlite_fetch_array

(

$query

,

SQLITE_ASSOC

);

sqlite_close

(

$db

);

$this

->

forward404Unless(

$this

->

attendee

);

}

(103)

symfony workshop www.symfony-project.com www.sensiolabs.com

<h2>Attendee #<?php

echo

$attendee

[

'id'

] ?></h2>

<p>

Name: <?php

echo

$attendee

[

'name'

] ?>

</p>

Exercise 11: The show action

(104)

URLs in actions

Forward to another action

$this

->

forward(

$moduleName

,

$actionName

);

$this

->

forward404Unless(

$condition

);

Redirect to another page

(105)

symfony workshop www.symfony-project.com www.sensiolabs.com

Access the request parameters

$param

=

$request

->

getParameter(

'id'

);

$module

=

$request

->

getParameter(

'module'

);

$action

=

$request

->

getParameter(

'action'

);

Create a URL

$url

=

$this

->

generateUrl(

$uri

);

URLs in actions

(106)

Redirect or Forward?

A forward does not change the user URL

A redirect involves a round-trip with the browser (302)

A forward can be used to create the same page with 2 URLs

After a post, you must always redirect

(107)

symfony workshop www.symfony-project.com www.sensiolabs.com

The DB connection opening code is duplicated

The DB connection closing code is duplicated

It’s a good practice to often refactor the code

Use the

preExecute()

and

postExecute()

methods

The goal is to simplify actions and make them thinner

Exercise 12: Clean the code

(108)

Exercise 12: Clean the code

public function

preExecute

()

{

define

(

'DB_FILE'

,

sfConfig

::

get(

'sf_data_dir'

)

.

'/data.db'

);

if

(

!

$this

->

db

=

sqlite_open

(

DB_FILE

,

0666

,

$error

))

{

die

(

$error

);

}

}

public function

postExecute

()

{

(109)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 12: Clean the code

public function

executeIndex

(

sfWebRequest

$request)

{

query

=

sqlite_query

($this

->

db,

'

SELECT

count(*)

FROM

attendee

'

);

$this

->

count

=

sqlite_fetch_single

($query);

$this

->

attendees

=

array

();

$query

=

sqlite_query

($this

->

db,

'

SELECT

*

FROM

attendee

'

);

while

($attendee

=

sqlite_fetch_array

($query,

SQLITE_ASSOC

))

{

$this

->

attendees[]

=

$attendee;

}

}

(110)

Exercise 12: Clean the code

public function

executeShow

(sfWebRequest

$request

)

{

$query

=

sqlite_query(

$this

->

db

,

'

SELECT

*

FROM

attendee

WHERE

id = '

.

$request

->

getParameter('id')

);

$this

->

attendee

=

sqlite_fetch_array(

$query

, SQLITE_ASSOC);

$this

->

forward404Unless(

$this

->

attendee

);

(111)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 12: Clean the code

public function

executeCreate

(

sfWebRequest

$request

)

{

if

(

$request

->

isMethod(

'post'

))

{

$name

=

$request

>

getParameter(

'name'

);

$query

=

sqlite_exec

(

$this

->

db

,

'

INSERT INTO

attendee (name)

VALUES

(

"'

.

$name

.

'")'

,

$error

);

if

(

!

$query

) {

die

(

"Error in query: '

$error

'"

);

}

}

$this

->

redirect(

'attendee/index'

);

}

(112)

Template names

Templates are stored under

templates/

The template name is the action name + a su

ffi

x

The su

ffi

x is returned by the action

class

myModule

extends

sfActions

{

public function

executeMyAction()

{

return

sfView

::

SUCCESS

;

}

(113)

symfony workshop www.symfony-project.com www.sensiolabs.com

Template names

class

myModuleActions

extends

sfActions

{

// myModule/templates/myActionSuccess.php

public function

executeMyAction

()

{

}

}

class

myModule

extends

sfActions

{

// myModule/templates/myActionError.php

public function

executeMyAction

()

{

return

sfView

::

ERROR

;

}

}

(114)

Template names

class

myModule

extends

sfActions

{

// myModule/templates/myActionFoobar.php

public function

executeMyAction

()

{

return

'Foobar'

;

}

(115)

symfony workshop www.symfony-project.com www.sensiolabs.com

Symfony templating system: PHP

Just works

Easy to understand and learn (plenty of docs)

Powerful (lots of built-in functions)

Extensible

Easy to integrate with the other objects

Readable

Opened to other templating systems

(116)

Exercise 13: Links between pages

Replace links in templates

Use the symfony

link_to()

and

url_for()

helpers

<h1>

<?php

echo

link_to('Attendee Application', 'attendee/index') ?>

</h1>

// …

<?php

foreach

(

$attendees

as

$attendee

): ?>

<tr>

<td>

<?php

echo

link_to(

$attendee

['id'], 'attendee/show?id='

.

$attendee

['id']) ?>

</td>

<td><?php

echo

$attendee

['name'] ?></td>

<th>

<?php

echo

link_to('delete', 'attendee/delete?id='

.

$attendee

['id']) ?>

</th>

(117)

symfony workshop www.symfony-project.com www.sensiolabs.com

Link to another action

Routed URL

<a

href="

/attendee/show/id/12

"

>

Click Me!

</a>

<?php echo link_to(

'Click Me!'

,

'attendee/show?id='

.

$id

) ?>

(118)

Template helpers

PHP functions

Wrap complex templating code

Shortcuts for common usages

(119)

symfony workshop www.symfony-project.com www.sensiolabs.com

Link helpers

The

url_for()

helper

Outputs in HTML as:

/articles/2007/02/19/symfony-rocks

<?php

echo

url_for(

'article/permalink?slug=symfony-rocks&day=19&month=02&year=2007'

) ?>

(120)

Link helpers

The

link_to()

helper

Outputs in HTML as

<a

href="

/articles/2007/02/19/symfony-rocks

"

>

symfony rocks!

</a>

<?php

echo

link_to(

'symfony rocks!'

,

'article/permalink?slug=symfony-rocks&day=19&month=02&year=2007'

) ?>

(121)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 14: The delete action

Change the delete link

<th>

<?php

echo

link_to(

'delete'

,

'attendee/delete?id='

.

$attendee

[

'id'

]) ?>

</th>

(122)

public function

executeDelete(sfWebRequest

$request

)

{

$query

=

sqlite_exec

(

$this

->

db

,

'

DELETE

FROM

attendee

WHERE

id

=

'

.

sqlite_escape_string

(

$request

->

getParameter(

'id'

)

),

$error

);

if

(

!

$query

)

{

die

(

"Error in query: '

$error

'"

);

}

$this

->

redirect(

'attendee/index'

);

(123)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 15: Fix images directoy

The link to create a new attendee or to come back to the

homepage is broken

image_tag()

takes the root directory of the project

installation into account

<?php

echo

image_tag(

'attendee.jpg'

) ?>

(124)

Contains data to manipulate

Contains all the business logic

Often associated with the database

Most important layer in MVC architecture

(125)

symfony workshop www.symfony-project.com www.sensiolabs.com

Create a

lib/AttendeeModel.class.php

file

Move the

preExecute()

code in

__construct()

method

Move the

postExecute()

code in

__destruct()

method

Store the DB connection in a private

$db

property

Exercise 16: The Model layer

(126)

Exercise 16: The Model layer

class

AttendeeModel

{

private

$db

;

public function

__construct

()

{

if

(

!

$this

->

db

=

sqlite_open

(

sfConfig

::

get(

'sf_data_dir'

)

.

'/data.db'

,

0666

,

$error

))

{

throw

new

Exception

(

'Unable to open DB connection: '

.

$error

);

}

}

public function

__destruct

()

{

if

(

$this

->

db

)

{

sqlite_close

(

$this

->

db

);

}

(127)

symfony workshop www.symfony-project.com www.sensiolabs.com

Remove

preExecute()

and

postExecute()

methods

Implement a

count()

method to count all attendees

Implement a

findAll()

method to find all attendees

Refactor the

executeIndex()

method consequently

Exercise 16: The Model layer

(128)

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

count

()

{

$query

=

sqlite_query

(

$this

->

db

,

'SELECT

COUNT(*)

FROM

attendee

'

);

return

(

int

)

sqlite_fetch_single

();

}

}

(129)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

findAll

()

{

$query

=

sqlite_query

(

$this

->

db

,

'SELECT

*

FROM

attendee

'

);

$attendees

=

array

();

while

(

$attendee

=

sqlite_fetch_assoc(

$query

,

SQLITE_ASSOC

))

{

$attendees

[]

=

$attendee

;

}

return

$attendees

;

}

}

lundi 15 mars 2010

(130)

Exercise 16: The Model layer

public function

executeIndex

(

sfWebRequest

$request

)

{

$attendeeTable

=

new

AttendeeModel

();

$this

->

count

=

$attendeeTable

->

count();

$this

->

attendees

=

$attendeeTable

->

findAll();

}

(131)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 16: The Model layer

Add a

create()

method that creates a new attendee

Add a

find()

method that finds an attendee by its id

Add a

delete()

method that deletes an attendee by its id

Refactor action methods consequently

(132)

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

find

($id)

{

$sql

=

sprintf

(

'

SELECT

*

FROM

attendee

WHERE

id = %u

'

, $id);

$query

=

sqlite_query

($this

->

db, $sql);

return

sqlite_fetch_array

($query,

SQLITE_ASSOC

);

}

(133)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

create

(

$name

)

{

$sql

=

sprintf

(

'INSERT INTO

attendee (name)

VALUES

(

"%s"

)

'

,

$name

);

$query

=

sqlite_query

(

$this

->

db

,

$sql

,

$error

);

if

(

!

$query

)

{

throw

new

Exception

(

'Unable to create a new attendee: '.

$error

);

}

}

}

(134)

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

delete

(

$id

)

{

$sql

=

sprintf

(

'DELETE

FROM

attendee

WHERE

id = %u

'

,

$id

);

$query

=

sqlite_query

(

$this

->

db

,

$sql

,

$error

);

if

(

!

$query

)

{

throw

new

Exception

(

'Unable to delete #'.

$id

.': '.

$error

);

}

(135)

symfony workshop www.symfony-project.com www.sensiolabs.com

Exercise 16: The Model layer

class

AttendeeModel

{

// ...

public function

delete

(

$id

)

{

$sql

=

sprintf

(

'DELETE

FROM

attendee

WHERE

id = %u

'

,

$id

);

$query

=

sqlite_query

(

$this

->

db

,

$sql

,

$error

);

if

(

!

$query

)

{

throw

new

Exception

(

'Unable to delete #'.

$id

.': '.

$error

);

}

}

}

(136)

Exercise 16: The Model layer

public function

executeIndex

(

sfWebRequest

$request

)

{

$attendeeTable

=

new

AttendeeModel

();

$this

->

count

=

$attendeeTable

->

count();

$this

->

attendees

=

$attendeeTable

->

findAll();

}

public function

executeShow

(

sfWebRequest

$request

)

{

$attendeeTable

=

new

AttendeeModel

();

$this

->

attendee

=

$attendeeTable

->

find(

$request

->

getParameter(

'id'

));

}

References

Related documents

S¨ussmuth, 2006, Effects of Inflation and Wealth Distribution: Do stock market participation fees and capital income taxation matter?, Journal of Economic Dynamics and Control

To investigate the role of the beta 2 adrenergic receptor ( b 2AR) in wound scarring, the ability of beta 2 adrenergic receptor agonist ( b 2ARag) to alter HDF differentiation

T he aim of this study is, on the one hand, to conduct a comparative analysis between the price of coffee and the price of oil products, and on the other hand, the relationship

Chile has some of the highest cancer screening levels in South America [ 6 , 7 ] but also a highly unequal healthcare system, in terms of its access.[ 8 , 9 ] Based on

This study aims at eliciting information on “Public Perceptions towards Billboard Advertising in Tanzania: The Case Study of Dar es Salaam City.” The research would be

Ann Handley, Chief Content Officer at MarketingProfs and author of the just published (November 2010) Content Rules: How to Create Killer Blogs, Podcasts,Videos,

This service allows a user to aggregate attributes and credentials from multiple Identity Providers (IdPs), allowing access to services that have access requirements that are

The key contributions of this paper are the description of Airavata’s overall design as a general purpose application and workflow management framework for science