Beruflich Dokumente
Kultur Dokumente
1 dari 16
SensioLabsNetwork (/)
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
Marketplace (/marketplace)
Jobs (/jobs)
Services (/services)
(/)
News (/blog/)
(http://sensiolabs.com)
DOWNLOAD (/DOWNLOAD)
The Cookbook
(/doc/2.6/cookbook
/index.html)
The Components
(/doc/2.6/components
/index.html)
Symfony Best Practices
(/doc/2.6
/best_practices
/index.html)
Reference (/doc/2.6
/reference/index.html)
Index (/doc/2.6
/genindex.html)
Contributing (/doc/2.6
/contributing
2.6 version
English
edit this page
(https://github.com
/symfony
/symfonydocs/edit
/2.6/book
/from_flat_php_to_symfony2.rst)
and then refactor it to be more organized. You'll travel through time, seeing
the decisions behind why web development has evolved over the past several
years to where it is now.
By the end, you'll see how Symfony can rescue you from mundane tasks and
let you take back control of your code.
/index.html)
Bundles
begin, create a single page that displays blog entries that have been persisted
(/doc/bundles/)
In this chapter, you'll build the token blog application using only flat PHP. To
to the database. Writing in flat PHP is quick and dirty:
Symfony CMF
(/doc/master
/cmf/index.html)
Docs for symfony 1.x
(/legacy/doc)
Trainings
(http://trainings.sensiolabs.com/)
Table of Contents
A Simple Blog in Flat
PHP
Isolating the
Presentation
Isolating the
Application (Domain)
Logic
Isolating the Layout
Adding a Blog "show"
12/1/2014 8:54 PM
2 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
Page
(/)
<?php
1
A "Front Controller" to
//index.php
2
theisRescue
What
Symfony? (/what-is-symfony)
Get started (/get-started) Documentation (/doc/current/index.html)
$link=mysql_connect('localhost','myuser','mypassword');
3
Creating the Front
mysql_select_db('blog_db',$link);
4
Controller
5
Community
(/community) Marketplace
(/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
Add a Touch of
Symfony
The Sample
Application in
Symfony
Where Symfony
Delivers
Better Templates
Learn more from the
Cookbook
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$result=mysql_query('SELECTid,titleFROMpost',$link);
?>
<!DOCTYPEhtml>
<html>
<head>
<title>ListofPosts</title>
</head>
<body>
<h1>ListofPosts</h1>
<ul>
<?phpwhile($row=mysql_fetch_assoc($result)):?>
<li>
<ahref="/show.php?id=<?phpecho$row['id']?>">
<?phpecho$row['title']?>
</a>
</li>
<?phpendwhile?>
</ul>
</body>
</html>
<?php
mysql_close($link);
?>
Master Symfony2
fundamentals
(http://trainings.sensiolabs.com
/en/training/gettingThat's quick to write, fast to execute, and, as your app grows, impossible to
started-with-symfony2)
Be trained by SensioLabs
maintain. There are several problems that need to be addressed:
experts (2 to 6 day sessions
-- French or English).
trainings.sensiolabs.com
(https://insight.sensiolabs.com)
12/1/2014 8:54 PM
3 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
<?php
1
//index.php
2
What
Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
3 is$link=mysql_connect('localhost','myuser','mypassword');
mysql_select_db('blog_db',$link);
4
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
$result=mysql_query('SELECTid,titleFROMpost',$link);
6
7
8
9
10
11
12
13
14
15
16
$posts=array();
while($row=mysql_fetch_assoc($result)){
$posts[]=$row;
}
mysql_close($link);
//includetheHTMLpresentationcode
require'templates/list.php';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPEhtml>
<html>
<head>
<title>ListofPosts</title>
</head>
<body>
<h1>ListofPosts</h1>
<ul>
<?phpforeach($postsas$post):?>
<li>
<ahref="/read?id=<?phpecho$post['id']?>">
<?phpecho$post['title']?>
</a>
</li>
<?phpendforeach?>
</ul>
</body>
</html>
By convention, the file that contains all of the application logic - index.php is known as a "controller". The term controller (../glossary.html#term-
In this case, the controller prepares data from the database and then includes
a template to present that data. With the controller isolated, you could easily
change just the template file if you needed to render the blog entries in some
other format (e.g. list.json.php for JSON format).
posts? Refactor the code so that the core behavior and data-access functions
of the application are isolated in a new file called model.php:
12/1/2014 8:54 PM
4 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
<?php
1
//model.php
2
What
Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
3 isfunctionopen_database_connection()
{
4
$link=mysql_connect('localhost','myuser','mypassword');
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
mysql_select_db('blog_db',$link);
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
return$link;
}
functionclose_database_connection($link)
{
mysql_close($link);
}
functionget_all_posts()
{
$link=open_database_connection();
$result=mysql_query('SELECTid,titleFROMpost',$link);
$posts=array();
while($row=mysql_fetch_assoc($result)){
$posts[]=$row;
}
close_database_connection($link);
return$posts;
}
The filename model.php is used because the logic and data access
of an application is traditionally known as the "model" layer. In a
1
2
3
4
5
6
<?php
require_once'model.php';
$posts=get_all_posts();
require'templates/list.php';
Now, the sole task of the controller is to get data from the model layer of the
application (the model) and to call a template to render that data. This is a
very simple example of the model-view-controller pattern.
The only part of the code that can't be reused is the page layout. Fix that by
12/1/2014 8:54 PM
5 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
creating
(/)a new layout.php file:
What is Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
<!templates/layout.php>
1
<!DOCTYPEhtml>
2
Community (/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
<html>
3
<head>
4
<title><?phpecho$title?></title>
5
</head>
6
<body>
7
<?phpecho$content?>
8
</body>
9
</html>
10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php$title='ListofPosts'?>
<?phpob_start()?>
<h1>ListofPosts</h1>
<ul>
<?phpforeach($postsas$post):?>
<li>
<ahref="/read?id=<?phpecho$post['id']?>">
<?phpecho$post['title']?>
</a>
</li>
<?phpendforeach?>
</ul>
<?php$content=ob_get_clean()?>
<?phpinclude'layout.php'?>
You've now introduced a methodology that allows for the reuse of the layout.
Unfortunately, to accomplish this, you're forced to use a few ugly PHP
functions (ob_start(), ob_get_clean()) in the template. Symfony uses a
organized and reusable. To prove it, add a blog "show" page, which displays
an individual blog post identified by an id query parameter.
12/1/2014 8:54 PM
6 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
//model.php
1
functionget_post_by_id($id)
2
What
3 is{ Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
$link=open_database_connection();
4
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
$id=intval($id);
6
$query='SELECTdate,title,bodyFROMpostWHEREid='.$id;
7
$result=mysql_query($query);
8
$row=mysql_fetch_assoc($result);
9
10
11
12
13
14
close_database_connection($link);
return$row;
}
Next, create a new file called show.php - the controller for this new page:
1
2
3
4
5
6
<?php
require_once'model.php';
$post=get_post_by_id($_GET['id']);
require'templates/show.php';
1
2
3
4
5
6
7
8
9
10
11
12
<?php$title=$post['title']?>
<?phpob_start()?>
<h1><?phpecho$post['title']?></h1>
<divclass="date"><?phpecho$post['date']?></div>
<divclass="body">
<?phpecho$post['body']?>
</div>
<?php$content=ob_get_clean()?>
<?phpinclude'layout.php'?>
Creating the second page is now very easy and no code is duplicated. Still,
this page introduces even more lingering problems that a framework can
solve for you. For example, a missing or invalid id query parameter will cause
the page to crash. It would be better if this caused a 404 page to be
rendered, but this can't really be done easily yet. Worse, had you forgotten to
clean the id parameter via the intval() function, your entire database would
be at risk for an SQL injection attack.
Another major problem is that each individual controller file must include the
model.php file. What if each controller file suddenly needed to include an
additional file or perform some other global task (e.g. enforce security)? As it
stands now, that code would need to be added to every controller file. If you
forget to include something in one file, hopefully it doesn't relate to
security...
controller): a single PHP file through which all requests are processed. With a
front controller, the URIs for the application change slightly, but start to
12/1/2014 8:54 PM
7 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
become
(/)more flexible:
What is Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
Withoutafrontcontroller
1
/index.php=>Blogpostlistpage(index.phpexecuted)
2
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
/show.php=>Blogpostshowpage(show.phpexecuted)
3
4
5
6
7
Withindex.phpasthefrontcontroller
/index.php=>Blogpostlistpage(index.phpexecuted)
/index.php/show=>Blogpostshowpage(index.phpexecuted)
When using a front controller, a single PHP file (index.php in this case) renders
every request. For the blog post show page, /index.php/show will actually
execute the index.php file, which is now responsible for routing requests
internally based on the full URI. As you'll see, a front controller is a very
powerful tool.
enough to render the blog post list page or the blog post show page based
on the requested URI:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//index.php
//loadandinitializeanygloballibraries
require_once'model.php';
require_once'controllers.php';
//routetherequestinternally
$uri=parse_url($_SERVER['REQUEST_URI'],PHP_URL_PATH);
if('/index.php'==$uri){
list_action();
}elseif('/index.php/show'==$uri&&isset($_GET['id'])){
show_action($_GET['id']);
}else{
header('Status:404NotFound');
echo'<html><body><h1>PageNotFound</h1></body></html>';
}
For organization, both controllers (formerly index.php and show.php) are now
PHP functions and each has been moved into a separate file, controllers.php:
12/1/2014 8:54 PM
8 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
functionlist_action()
1
{
2
What
Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
3 is$posts=get_all_posts();
require'templates/list.php';
4
}
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
6
functionshow_action($id)
7
{
8
$post=get_post_by_id($id);
9
require'templates/show.php';
10
}
11
As a front controller, index.php has taken on an entirely new role, one that
includes loading the core libraries and routing the application so that one of
In reality, the front controller is beginning to look and act a lot like Symfony's
mechanism for handling and routing requests.
By now, the application has evolved from a single PHP file into a structure that
is organized and allows for code reuse. You should be happier, but far from
satisfied. For example, the "routing" system is fickle, and wouldn't recognize
that the list page (/index.php) should be accessible also via / (if Apache
rewrite rules were added). Also, instead of developing the blog, a lot of time
is being spent working on the "architecture" of the code (e.g. routing, calling
controllers, templates, etc.). More time will need to be spent to handle form
submissions, input validation, logging and security. Why should you have to
reinvent solutions to all these routine problems?
it. This can be done by using Composer, which takes care of downloading the
correct version and all its dependencies and provides an autoloader. An
autoloader is a tool that makes it possible to start using PHP classes without
explicitly including the file containing the class.
In your root directory, create a composer.json file with the following content:
1
2
3
4
5
6
7
8
{
"require":{
"symfony/symfony":"2.5.*"
},
"autoload":{
"files":["model.php","controllers.php"]
}
}
12/1/2014 8:54 PM
9 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
$phpcomposer.pharinstall
Documentation (/doc/current/index.html)
vendor/autoload.php
file, which
takes(/marketplace)
care of autoloading
for all the
files(/services)
in
Community (/community)
Marketplace
Jobs (/jobs)
Services
the Symfony Framework as well as the files mentioned in the autoload section
News (/blog/)
of your composer.json.
interpret each request and return a response. To this end, Symfony provides
both a Request(http://api.symfony.com/2.6/Symfony/Component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
//index.php
require_once'vendor/autoload.php';
useSymfony\Component\HttpFoundation\Request;
useSymfony\Component\HttpFoundation\Response;
$request=Request::createFromGlobals();
$uri=$request>getPathInfo();
if('/'==$uri){
$response=list_action();
}elseif('/show'==$uri&&$request>query>has('id')){
$response=show_action($request>query>get('id'));
}else{
$html='<html><body><h1>PageNotFound</h1></body></html>';
$response=newResponse($html,Response::HTTP_NOT_FOUND);
}
//echotheheadersandsendtheresponse
$response>send();
2.4 Support for HTTP status code constants was introduced in Symfony
2.4.
The controllers are now responsible for returning a Response object. To make
this easier, you can add a new render_template() function, which, incidentally,
acts quite a bit like the Symfony templating engine:
12/1/2014 8:54 PM
10 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
//controllers.php
1
useSymfony\Component\HttpFoundation\Response;
2
What
3 is Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
functionlist_action()
4
{
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
$posts=get_all_posts();
6
$html=render_template('templates/list.php',array('posts'=>$posts)
7
8
9
returnnewResponse($html);
10
}
11
12
functionshow_action($id)
13
{
14
$post=get_post_by_id($id);
15
$html=render_template('templates/show.php',array('post'=>$post));
16
17
returnnewResponse($html);
18
}
19
20
//helperfunctiontorendertemplates
21
functionrender_template($path,array$args)
22
{
23
extract($args);
24
ob_start();
25
require$path;
26
$html=ob_get_clean();
27
28 return$html;
29 }
simple application. Along the way, you've made a simple routing system and a
method using ob_start() and ob_get_clean() to render templates. If, for some
reason, you needed to continue building this "framework" from scratch, you
could at least use Symfony's standalone Routing (https://github.com
/symfony/Routing) and Templating (https://github.com/symfony
/Templating) components, which already solve these problems.
Instead of re-solving common problems, you can let Symfony take care of
them for you. Here's the same sample application, now built in Symfony:
12/1/2014 8:54 PM
11 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
//src/AppBundle/Controller/BlogController.php
1
namespaceAppBundle\Controller;
2
What
3 is Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
useSymfony\Bundle\FrameworkBundle\Controller\Controller;
4
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
classBlogControllerextendsController
6
{
7
publicfunctionlistAction()
8
{
9
$posts=$this>get('doctrine')
10
>getManager()
11
>createQuery('SELECTpFROMAcmeBlogBundle:Postp')
12
>execute();
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
return$this>render('Blog/list.html.php',array('posts'=>$posts
}
publicfunctionshowAction($id)
{
$post=$this>get('doctrine')
>getManager()
>getRepository('AppBundle:Post')
>find($id);
if(!$post){
//causethe404pagenotfoundtobedisplayed
throw$this>createNotFoundException();
}
return$this>render('Blog/show.html.php',array('post'=>$post))
}
}
The two controllers are still lightweight. Each uses the Doctrine ORM library
(doctrine.html) to retrieve objects from the database and the Templating
component to render a template and return a Response object. The list
template is now quite a bit simpler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!app/Resources/views/Blog/list.html.php>
<?php$view>extend('layout.html.php')?>
<?php$view['slots']>set('title','ListofPosts')?>
<h1>ListofPosts</h1>
<ul>
<?phpforeach($postsas$post):?>
<li>
<ahref="<?phpecho$view['router']>generate(
'blog_show',
array('id'=>$post>getId())
)?>">
<?phpecho$post>getTitle()?>
</a>
</li>
<?phpendforeach?>
</ul>
12/1/2014 8:54 PM
12 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
<!app/Resources/views/layout.html.php>
1
<!DOCTYPEhtml>
2
What
Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
3 is<html>
<head>
4
<title><?phpecho$view['slots']>output(
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
'title',
6
'Defaulttitle'
7
)?></title>
8
</head>
9
<body>
10
<?phpecho$view['slots']>output('_content')?>
11
</body>
12
</html>
13
When Symfony's engine (called the Kernel) boots up, it needs a map so that it
knows which controllers to execute based on the request information. A
1
2
3
4
5
6
7
8
#app/config/routing.yml
blog_list:
path:/blog
defaults:{_controller:AppBundle:Blog:list}
blog_show:
path:/blog/show/{id}
defaults:{_controller:AppBundle:Blog:show}
Now that Symfony is handling all the mundane tasks, the front controller is
dead simple. And since it does so little, you'll never have to touch it once it's
created (and if you use a Symfony distribution, you won't even need to create
it!):
1
2
3
4
5
6
7
8
//web/app.php
require_once__DIR__.'/../app/bootstrap.php';
require_once__DIR__.'/../app/AppKernel.php';
useSymfony\Component\HttpFoundation\Request;
$kernel=newAppKernel('prod',false);
$kernel>handle(Request::createFromGlobals())>send();
The front controller's only job is to initialize Symfony's engine (Kernel) and
pass it a Request object to handle. Symfony's core then uses the routing map
to determine which controller to call. Just like before, the controller method is
responsible for returning the final Response object. There's really not much
else to it.
For a visual representation of how Symfony handles each request, see the
request flow diagram (http_fundamentals.html#request-flow-figure).
12/1/2014 8:54 PM
13 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
works (/)
and the recommended organization of a project. For now, have a look
at how migrating the blog from flat PHP to Symfony has improved life:
What is Symfony? (/what-is-symfony)
Documentation (/doc/current/index.html)
Your application now has clear and consistently organized code (though
Community
(/marketplace)
Jobs (/jobs)
Services
Symfony(/community)
doesn't forceMarketplace
you into this).
This promotes
reusability
and(/services)
News (/blog/)
100% of the code you write is for your application. You don't need to
develop or maintain low-level utilities such as autoloading
(page_creation.html#autoloading-introduction-sidebar), routing
(routing.html), or rendering controllers (controller.html);
Symfony gives you access to open source tools such as Doctrine and the
Templating, Security, Form, Validation and Translation components (to
name a few);
And perhaps best of all, by using Symfony, you now have access to a whole
set of high-quality open source tools developed by the Symfony
Better Templates
If you choose to use it, Symfony comes standard with a templating engine
called Twig (http://twig.sensiolabs.org) that makes templates faster to write
and easier to read. It means that the sample application could contain even
less code! Take, for example, the list template written in Twig:
{#app/Resources/views/Blog/list.html.twig#}
{%extends"layout.html.twig"%}
1
2
3
4
5
6
7
8
9
10
11
12
13
{%blockbody%}
<h1>ListofPosts</h1>
<ul>
{%forpostinposts%}
<li>
<ahref="{{path('blog_show',{'id':post.id})}}">
{{post.title}}
</a>
14
15
16
17
</li>
{%endfor%}
</ul>
{%endblock%}
{%blocktitle%}ListofPosts{%endblock%}
12/1/2014 8:54 PM
14 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
{#app/Resources/views/layout.html.twig#}
1
<!DOCTYPEhtml>
2
What
Symfony? (/what-is-symfony) Get started (/get-started) Documentation (/doc/current/index.html)
3 is<html>
<head>
4
<title>{%blocktitle%}Defaulttitle{%endblock%}</title>
5
Community
(/community) Marketplace (/marketplace) Jobs (/jobs) Services (/services) News (/blog/)
</head>
6
<body>
7
{%blockbody%}{%endblock%}
8
</body>
9
</html>
10
In the news
Getting Started
with Symfony2
(/blog/symfony-2-6-0-released)
Heverlee -
(/blog/symfony-2-6-0-beta2released)
(/blog/a-week-of-symfony-
412-17-23-november-2014)
Visit The Symfony Blog (/blog/)
Upcoming training
sessions
2014-12-01
(http://sensiolabs.com
/en/symfony/certification.html)
Symfony Certification: Now in
4,000 centers around the world!
GET CERTIFIED
(http://sensiolabs.com
/en/symfony/certification
/order)
(http://training.sensiolabs.com
/en/training
/courses?search_training%5Blevel
%5D%5B0%5D=beginner&
search_training%5Bduration%5D=2&
search_training%5BavailableLanguages
%5D%5B0%5D=fr&
search_training%5BavailableLanguages
%5D%5B1%5D=en&
search_training%5BavailableLanguages
%5D%5B2%5D=de&
search_training%5BavailableLanguages
%5D%5B3%5D=es&
search_training%5Bkeywords%5D=D
%C3%A9marrer+avec+Symfony2&
search_training%5Bfrom%5D=12%2F0
12/1/2014 8:54 PM
15 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
(/)
search_training%5Bto%5D=12%2F02%2F2014)
Getting Started
with Symfony2
Clichy - 2014-12-01
Community (/community)
Marketplace (/marketplace)
(http://training.sensiolabs.com
Documentation (/doc/current/index.html)
Jobs (/jobs)
Services (/services)
News (/blog/)
/en/training
/courses?search_training%5Blevel
%5D%5B0%5D=beginner&
search_training%5Bduration%5D=2&
search_training%5BavailableLanguages
%5D%5B0%5D=fr&
search_training%5BavailableLanguages
%5D%5B1%5D=en&
search_training%5BavailableLanguages
%5D%5B2%5D=de&
search_training%5BavailableLanguages
%5D%5B3%5D=es&
search_training%5Bkeywords%5D=D
%C3%A9marrer+avec+Symfony2&
search_training%5Bfrom%5D=12%2F01%2F2014&
search_training%5Bto%5D=12%2F02%2F2014)
View all sessions
(http://trainings.sensiolabs.com/)
Index (/doc/2.6/genindex.html)
Contributing (/doc/2.6/contributing
/index.html)
Bundles (/doc/bundles/)
License (/doc/current/contributing
/code/license.html)
Roadmap (/roadmap)
Logo (/logo)
Trademark & Logo Policy (/trademark)
Community (/community)
Services (/services)
SensioLabs Connect
(https://connect.sensiolabs.com/)
Train developers
(http://trainings.sensiolabs.com/en)
Forum (http://forum.symfonyproject.org/)
Support (http://sensiolabs.com
12/1/2014 8:54 PM
16 dari 16
http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
Contributors
(/) (/contributors)
Blog
(/blog/)
What
is Symfony? (/what-is-symfony)
A week of symfony (/blog/category
/a-week-of-symfony)
Community (/community)
/en/support/sensiolabs_support.html)
About (/about)
Contact us (/services/request)
SensioLabs (http://sensiolabs.com
Marketplace (/marketplace)
/recrutement/rejoignez_nous.html)
Documentation (/doc/current/index.html)
Jobs (/jobs)
Contributors (/contributors)
Roadmap (/roadmap)
Services (/services)
News (/blog/)
Documentation (/blog/category
/documentation)
Living on the edge (/blog/category
/living-on-the-edge)
Releases (/blog/category/releases)
Security Advisories (/blog/category
/security-advisories)
12/1/2014 8:54 PM