SlideShare ist ein Scribd-Unternehmen logo
1 von 65
Downloaden Sie, um offline zu lesen
Symfony2
The Unofficial “Best” Practices
Gerry Vandermaesen
AKA
How Gerry Does Symfony2
About Me
• Developer and trainer at King Foo
• SensioLabs Certified Symfony Developer
• We develop tailor-made PHP applications
• @gerryvdm / gerry@king-foo.be
The Official Best Practices
• Excellent guidelines for beginning Symfony
developers
• Use a single bundle for application specific
code
• Use the app/Resources/views/ directory for
all application specific templates
• Use YAML for application configuration
Keep your Business Logic
Outside Bundles
• Your business logic hopefully outlives
Symfony2
• Keep your model agnostic / decoupled from
the framework (and ORM)
Keep Mapping and Validation Configuration

Outside Entity Classes
=
Do Not Use Annotations
# config.yml 

doctrine:

orm:

auto_mapping: false

mappings:

model:

type: yml

prefix: KingFooPresentationModel

dir: %kernel.root_dir%/config/doctrine

alias: Model
Tip:

Defining Constraints in

app/config/validation.yml
use SymfonyComponentDependencyInjectionCompilerCompilerPassInterface;

use SymfonyComponentDependencyInjectionContainerBuilder;



class RegisterValidationMappingsPass implements CompilerPassInterface

{

public function process(ContainerBuilder $container)

{

if ($container->hasDefinition('validator.builder')) {

$file = $container->getParameter('kernel.root_dir') .

'/config/validation.yml';



$container->getDefinition('validator.builder')

->addMethodCall('addYamlMappings', [$file]);

}

}

}
Combo-Tip:
Defining Constraints in

app/config/validation/*.yml
use SymfonyComponentDependencyInjectionCompilerCompilerPassInterface;

use SymfonyComponentDependencyInjectionContainerBuilder;

use SymfonyComponentFinderFinder;



class RegisterValidationMappingsPass implements CompilerPassInterface

{

public function process(ContainerBuilder $container)

{

if ($container->hasDefinition('validator.builder')) {

$dir = $container->getParameter('kernel.root_dir') .

'/config/validation';



$finder = new Finder();

$finder->files()->name('*.yml')->in($dir);



$files = [];



foreach ($finder as $file) {

$files[] = $file->getRealPath();

}



if (count($files)) {

$container->getDefinition('validator.builder')

->addMethodCall('addYamlMappings', [$files]);

}

}

}

}
The Front Controller
$kernel = new AppKernel('prod', false);
use SymfonyComponentDebugDebug;
$env = getenv('SYMFONY_ENV') ?: 'prod';

$debug = getenv('SYMFONY_DEBUG') === '1' && $env !== 'prod';
if ($debug) {

Debug::enable();

}
$kernel = new AppKernel($env, $debug);
<VirtualHost *:80>

# ...

SetEnv SYMFONY_ENV dev

SetEnv SYMFONY_DEBUG 1

</VirtualHost>
server {

location /app.php {

# ...

fastcgi_param SYMFONY_ENV dev;

fastcgi_param SYMFONY_DEBUG 1;

}

}
Apache
Nginx
Taking It One Step Further
server {

# ...



location / {

try_files $uri @app;

}



location @app {

fastcgi_pass unix:/var/run/php5-fpm.sock;

include fastcgi_params;



fastcgi_param SCRIPT_FILENAME /path/to/project/app/app.php;

fastcgi_param SCRIPT_NAME /path/to/project/app/app.php;



fastcgi_param SYMFONY_ENV dev;

fastcgi_param SYMFONY_DEBUG 1;

}

}

Use PSR-4 for
the `src/` Directory
{

"autoload": {

"psr-4": { "KingFooPresentation": "src/" }

}

}
💫
Prevent Autoloading of

Tests in Production
{

"autoload": {

"psr-4": { "KingFooPresentation": "src/" }

},

"autoload-dev": {

"psr-4": { “KingFooPresentationTests”: "tests/" }

}

}

Add Requirements to
your Routes
# routing.yml

homepage:

path: /{_locale}



ticket_index:

path: /{_locale}/tickets



tickets_detail:

path: /{_locale}/tickets/{id}



tickets_create:

path: /{_locale}/tickets/create



login:

path: /login
# routing.yml

homepage:

path: /{_locale}

requirements: { _locale: "(nl|fr|en)" }



ticket_index:

path: /{_locale}/tickets

requirements: { _locale: "(nl|fr|en)" }



tickets_detail:

path: /{_locale}/tickets/{id}

requirements: { _locale: "(nl|fr|en)", id: "[1-9][0-9]*" }



tickets_create:

path: /{_locale}/tickets/create

requirements: { _locale: "(nl|fr|en)" }



login:

path: /login
Regex 😕
Global “Requirements”
use SymfonyComponentHttpKernelEventGetResponseEvent;

use SymfonyComponentHttpKernelExceptionNotFoundHttpException;



class CheckLocaleListener

{

private $availableLocales;



public function __construct(array $availableLocales)

{

$this->availableLocales = $availableLocales;

}



public function checkLocale(GetResponseEvent $event)

{

$request = $event->getRequest();



if ($locale = $request->attributes->get('_locale')) {

if (!in_array($locale, $this->availableLocales)) {

throw new NotFoundHttpException();

}

}

}

}
# services.yml

parameters:

available_locales: [nl, fr, en]



services:

check_locale_listener:

class: CheckLocaleListener

arguments: [%available_locales%]

tags:

- name: kernel.event_listener

event: kernel.request

method: checkLocale

priority: 24
Bring Order in your
Services Configuration
# services.yml



# 500 lines of service declarations...
# services.yml

imports:

- { resource: services/controllers.yml }

- { resource: services/event_listeners.yml }

- { resource: services/repositories.yml }

Try Defining Your Services
as Private
# services.yml

services:

my_fantastic_service:

class: KingFooPresentationFantasticService

public: false
class DependentService extends ContainerAware

{

public function doSomething()

{

$this->container->get('my_fantastic_service')

->doSomethingElse();

}

}
class DependentService

{

public function __construct(FantasticService $service)

{

$this->service = $service;

}



public function doSomething()

{

$this->service->doSomethingElse();

}

}
Define your Repositories
as Services
# repositories.yml

services:

abstract_repository:

abstract: true

factory_service: doctrine.orm.entity_manager

factory_method: getRepository

public: false

blog_post_repository:

parent: abstract_repository

class: KingFooPresentationRepositoryBlogPostRepository

arguments: [Model:BlogPost]

comment_repository:

parent: abstract_repository

class: KingFooPresentationRepositoryCommentRepository

arguments: [Model:Comment]
Define your Controllers
as Services
# controllers.yml

services:

blog_post_controller:

class: KingFooPresentationControllerBlogPostController

arguments:

- @blog_post_repository

- @doctrine.orm.entity_manager
One Controller One Action
# controllers.yml

services:

blog_post_list_controller:

class: KingFooPresentationControllerBlogPostListController

arguments: [@blog_post_repository]

blog_post_create_controller:

class: KingFooPresentationControllerBlogPostCreateController

arguments: [@doctrine.orm.entity_manager]
<?php



namespace KingFooPresentationControllerBlogPost;



use DoctrineCommonPersistenceObjectManager;

use SymfonyComponentHttpFoundationRequest;



class CreateController

{

public function __construct(ObjectManager $manager)

{

// ...

}



public function __invoke(Request $request)

{

// ...

}

}
Annotate your Controllers
public function __invoke(Request $request)

{

if (!$this->authorizationChecker->isGranted('ROLE_EDITOR')) {

throw new AccessDeniedHttpException();

}



$response = new Response();

$response->setMaxAge(3600);



return $this->templating->renderResponse(

'blog_post/create.html.twig',

array(

// view parameters

),

$response

);

}
use SensioBundleFrameworkExtraBundleConfigurationCache;

use SensioBundleFrameworkExtraBundleConfigurationRoute;

use SensioBundleFrameworkExtraBundleConfigurationSecurity;

use SensioBundleFrameworkExtraBundleConfigurationTemplate;



/**

* @Route(service="blog_post_create_controller")

*/

class CreateController

{

/**

* @Route("/blog/create", name="foo")

* @Cache(maxage=3600)

* @Security("has_role('ROLE_EDITOR')")

* @Template("blog_post/create.html.twig")

*/

public function __invoke(Request $request)

{

return array(

// view parameters

);

}

}
Never Circumvent the
Framework
class BadController

{

public function __invoke()

{

$template = $_GET['template'];

setcookie('lastGeneration', time());



$this->archaicPdfLib->output($template);

exit;

}

}
use SymfonyComponentHttpFoundationCookie;

use SymfonyComponentHttpFoundationRequest;

use SymfonyComponentHttpFoundationStreamedResponse;



class BetterController

{

public function __invoke(Request $request)

{

$template = $request->query->get('template');



$response = new StreamedResponse(

function() use ($template) {

$this->archaicPdfLib->output($template);

}

);



$cookie = new Cookie('lastGeneration', time());

$response->headers->setCookie($cookie);



return $response;

}

}
Securing your Application
Avoid usage of
`access_control` in
security.yml
access_control:

- { path: ^/(nl|fr|en)/admin, roles: ROLE_ADMIN }
Regex 😕
class AdminController

{

/**

* @Route("/{_locale}/admin")

* @Security("has_role('ROLE_ADMIN')")

*/

public function __invoke(Request $request)

{

// if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {

// throw new AccessDeniedHttpException();

// }



// ..

}

}
Use Bcrypt
# security.yml

security:

encoders:

KingFooPresentationSecurityUser:

algorithm: bcrypt

cost: 13
# services.yml

services:

password_encoder:

class: SymfonyComponentSecurity...BCryptPasswordEncoder

arguments: [13]



# security.yml

security:

encoders:

KingFooPresentationSecurityUser:

id: password_encoder
Create Your Own Symfony
Framework Edition
• Remove clutter
• Add/remove default dependencies
• Customize default configuration
• Fork symfony/symfony-standard
• Make modifications
• Modify composer.json package name
• Publish on GitHub and Packagist
{

"name": "kingfoo/symfony-project",

"autoload": {

"psr-4": { "": "src/" }

},

"require": {

"php": ">=5.5.0",

"symfony/symfony": "~2.6",

"doctrine/mongodb-odm": "~1.0@dev",

"doctrine/mongodb-odm-bundle": "~3.0@dev",

"symfony/monolog-bundle": "~2.4",

"sensio/distribution-bundle": "~3.0,>=3.0.12",

"sensio/framework-extra-bundle": "~3.0",

"incenteev/composer-parameter-handler": "~2.0"

},

"require-dev": {

"phpunit/phpunit": "~4.4"

}

}
Miscellaneous / Flamebait
• Bundles are for extending the container and
configuring (third-party) libraries that are
reusable across projects in the container.
• Try doing without bundles for project-
specific configuration.
• YAML is the preferred configuration file
format for application-specific config, XML
for configuration of bundles
Develop Your Own

Best Practices
• Do it as a team
• Write them down
• Be consistent
• Learn regex 😉
Next Symfony Training
• Getting Started with Symfony2
• 12-13th February 2015
• Aarschot
• Leave your name + email for a €50 reduction
Questions? 🙉

Weitere ähnliche Inhalte

Andere mochten auch

Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP Streams
Davey Shafik
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!
tlrx
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)
Arnauld Loyer
 

Andere mochten auch (20)

CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 
Design pattern in Symfony2 - Nanos gigantium humeris insidentes
Design pattern in Symfony2 - Nanos gigantium humeris insidentesDesign pattern in Symfony2 - Nanos gigantium humeris insidentes
Design pattern in Symfony2 - Nanos gigantium humeris insidentes
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Elastic Searching With PHP
Elastic Searching With PHPElastic Searching With PHP
Elastic Searching With PHP
 
Diving deep into twig
Diving deep into twigDiving deep into twig
Diving deep into twig
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages web
 
Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP Streams
 
PHP5.5 is Here
PHP5.5 is HerePHP5.5 is Here
PHP5.5 is Here
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phing
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performance
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQL
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)
 
Caching on the Edge
Caching on the EdgeCaching on the Edge
Caching on the Edge
 
Performance serveur et apache
Performance serveur et apachePerformance serveur et apache
Performance serveur et apache
 

Kürzlich hochgeladen

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 

Kürzlich hochgeladen (20)

04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 

Symfony2 - The Unofficial "Best" Practices