SlideShare a Scribd company logo
1 of 110
Download to read offline
The Naked Bundle 
Matthias Noback 
@matthiasnoback
What's it all about?
An actual naked bundle
I could've called it 
BundleLitetm 
The No Code Bundle 
The Clean Bundle
But “naked” is catchy and controversial
The official view on bundles
First-class citizens 
Documentation » The Quick Tour » The Architecture
Importance 
Your code is more important than 
the framework, 
which is an implementation detail
Reuse
Nice!
All your code lives in a bundle 
Documentation » The Book » Creating Pages in Symfony2
Reuse 
“All your code in a bundle” 
contradicts the promise of reuse
Everything lives inside a bundle 
Documentation » Glossary
Not really true 
Many things live inside libraries 
(the Symfony components are 
libraries too!)
Which is good!
But you probably know that already
“libraries first”
What about... 
● Controllers 
● Entities 
● Templates 
● ...
They just need to be in a bundle 
Or do they?
Don't get me wrong 
I love Symfony!
But a framework is just a framework 
● Quickstarter for your projects 
● Prevents and solves big security 
issues for you 
● Has a community you can rely on
A framework is there for you
Your code doesn't need a framework
Noback's Principle 
Code shouldn't rely on something 
it doesn't truly need
Bundle conventions 
Things in a bundle often rely on 
conventions to work
Conventions aren't necessary at all
So according to Noback's Principle, 
code shouldn't rely on bundle conventions too
Naming conventions 
Controllers: 
● *Controller classes 
● *action methods 
Templates: 
● in /Resources/views 
● name: Controller/Action.html.twig
Structural conventions 
Controller: 
● Extends framework Controller class 
● Is ContainerAware
Behavioral conventions 
Controller: 
● Is allowed to return an array 
● Actions can type-hint to objects which will be 
fetched based on route parameters (??)
Configuration conventions 
Use lots of annotations! 
/** 
* @Route("/{id}") 
* @Method("GET") 
* @ParamConverter("post", class="SensioBlogBundle:Post") 
* @Template("SensioBlogBundle:Annot:show.html.twig") 
* @Cache(smaxage="15", lastmodified="post.getUpdatedAt()") 
* @Security("has_role('ROLE_ADMIN')") 
*/ 
public function showAction(Post $post) 
{ 
}
These conventions are what makes an application 
a Symfony2 application
A Year With Symfony
About bundles
A bundle exposes resources
Resources 
● Service definitions 
● Controllers 
● Routes 
● Templates 
● Entities 
● Form types 
● Event listeners 
● Translations 
● ...
No need for them to be inside a bundle
When placed outside the bundle 
the resources could be reused separately
The bundle would be really small
And could just as well be a: 
Laravel package, 
Zend or Drupal module, 
CakePHP plugin, 
...
So the challenge is to 
Make the bundle as clean as possible
Move the “misplaced” things to 
● a library 
● with dependencies 
● but not symfony/framework­bundle 
;)
Being realistic 
Practical reusability
Reuse within the Symfony family 
Think: Silex, Laravel, etc.
Allowed dependency 
HttpFoundation 
● Request 
● Response 
● Exceptions 
● etc.
What do we rely on 
HttpKernel 
namespace SymfonyComponentHttpKernel; 
use SymfonyComponentHttpFoundationRequest; 
use SymfonyComponentHttpFoundationResponse; 
interface HttpKernelInterface 
{ 
/** 
* Handles a Request to convert it to a Response. 
*/ 
public function handle(Request $request, ...); 
}
Why? My secret missions 
“Let's rebuild the application, but 
this time we use Zend4 instead of 
Symfony2”
And of course 
Education
You need a strong coupling radar
Explicit dependencies 
● Function calls 
● Imported classes (“use”) 
● Included files 
● ...
Implicit dependencies 
● File locations 
● File, class, method names 
● Structure of return values 
● ...
There we go!
use SymfonyBundleFrameworkBundleControllerController; 
use SensioBundleFrameworkExtraBundleConfigurationRoute; 
use SensioBundleFrameworkExtraBundleConfigurationTemplate; 
/** 
* @Route(“/article”) 
*/ 
class ArticleController extends Controller 
{ 
/** 
* @Route(“/edit”) 
* @Template() 
*/ 
function editAction(...) 
{ 
... 
} 
} 
Controller
TODO 
✔ Don't rely on things that may not 
be there in another context: 
✔ Parent Controller class 
✔ Routing, template, annotations, etc.
class ArticleController 
{ 
function editAction(...) 
{ 
... 
} 
} 
Nice and clean ;)
use SymfonyComponentHttpFoundationRequest; 
class ArticleController 
{ 
public function editAction(Request $request) 
{ 
$em = $this­> 
get('doctrine')­> 
getManager(); 
... 
if (...) { 
throw $this­> 
createNotFoundException(); 
} 
... 
return array( 
'form' => $form­> 
createView() 
); 
} 
} 
Zooming in a bit
TODO 
✔ Inject dependencies 
✔ Don't use helper methods 
✔ Render the template manually 
✔ Keep using Request 
(not really a TODO)
use DoctrineORMEntityManager; 
class ArticleController 
{ 
function __construct( 
EntityManager $em, 
) { 
$this­> 
em = $em; 
} 
... 
} 
Inject dependencies
Inline helper methods 
use SymfonyComponentHttpKernelExceptionNotFoundHttpException 
class ArticleController 
{ 
... 
public function newAction(...) 
{ 
... 
throw new NotFoundHttpException(); 
... 
} 
}
use SymfonyComponentHttpFoundationResponse; 
use SymfonyComponentTemplatingEngineInterface; 
class ArticleController 
{ 
function __construct(..., EngineInterface $templating) { 
} 
public function newAction(...) 
{ 
... 
return new Response( 
$this­> 
templating­> 
render( 
'@MyBundle:Article:new.html.twig', 
array( 
'form' => $form­> 
createView() 
) 
) 
); 
} 
} 
Render the template manually
Dependencies are explicit now 
Also: no mention of a “bundle” 
anywhere! 
use SymfonyComponentHttpFoundationRequest; 
use SymfonyComponentHttpFoundationResponse; 
use SymfonyComponentTemplatingEngineInterface; 
use DoctrineORMEntityManager;
Dependency overflow 
use SymfonyComponentHttpFoundationResponse; 
use SymfonyComponentTemplatingEngineInterface; 
class ArticleController 
{ 
function __construct( 
EntityManager $entityManager, 
EngineInterface $templating, 
TranslatorInterface $translator, 
ValidatorInterface $validator, 
Swift_Mailer $mailer, 
RouterInterface $router 
) { 
... 
} 
... 
}
The cause? 
Convention
One controller, many actions 
one action!
__invoke() 
namespace MyLibraryControllerArticle; 
class New 
{ 
function __construct(...) 
{ 
// only what's necessary for this “action” 
} 
public function __invoke(...) 
{ 
... 
} 
}
Nice! 
└─Controller 
└─Article 
├─New.php 
├─Edit.php 
├─Archive.php 
└─Delete.php
TODO 
✔ Set up routing 
✔ Create a service and provide the 
right arguments
Bundle stuff: services.xml 
<!­­in 
MyBundle/Resources/config/services.xml → 
<?xml version="1.0" ?> 
<container> 
<services> 
<service id="new_article_controller" 
class="MyBundleControllerArticleNew"> 
<argument type="service" 
id="doctrine.orm.default_entity_manager" /> 
<argument type="service" id="templating" /> 
</service> 
</services> 
</container>
Bundle stuff: routing.xml 
<!­­in 
MyBundle/Resources/config/routing.xml → 
<?xml version="1.0" encoding="UTF­8" 
?> 
<routes> 
<route id="new_article" 
path="/article/new"> 
<default key="_controller"> 
new_article_controller:__invoke 
</default> 
</route> 
</routes> 
Pull request by Kevin Bond allows you to leave out the “:__invoke” part!
Controller – Achievements 
● Can be anywhere 
● No need to follow naming conventions 
(“*Controller”, “*action”) 
● Dependency injection, no service location 
● Reusable in any application using 
HttpFoundation
Next up: Entities
namespace MyBundleEntity; 
use DoctrineORMMapping as ORM; 
class Article 
{ 
... 
/** 
* @ORMColumn(type=”string”) 
*/ 
private $title; 
} 
Entity conventions
What's wrong with annotations? 
namespace MyBundleEntity; 
use DoctrineORMMapping as ORM; 
class Article 
{ 
... 
/** 
* @ORMColumn(type=”string”) 
*/ 
private $title; 
}
Annotations are classes
use DoctrineCommonAnnotationsAnnotationReader; 
$reader = new AnnotationReader(); 
$class = new ReflectionClass('Article'); 
$reader­> 
getClassAnnotations($class); 
BANG 
Class 
DoctrineORMMappingColumn 
not found
Well, uhm, yes, but...
Are you ever going to use 
anything else than Doctrine ORM?
Well... 
Think about Doctrine MongoDB ODM, 
Doctrine CouchDB ODM, etc. 
namespace MyBundleEntity; 
use DoctrineORMMapping as ORM; 
use DoctrineODMMongoDBMappingAnnotations as MongoDB; 
use DoctrineODMCouchDBMappingAnnotations as CoucheDB; 
class Article 
{ 
/** 
* @ORMColumn 
* @MognoDBField 
* @CoucheDBField 
*/ 
private $title; 
}
TODO 
✔ Remove annotations 
✔ Find another way to map the data
namespace MyBundleEntity; 
class Article 
{ 
private $id; 
private $title; 
} 
Nice and clean 
A true POPO, the ideal of the data 
mapper pattern
Use XML for mapping metadata 
<doctrine­mapping> 
<entity name=”MyBundleEntityArticle”> 
<id name="id" type="integer" column="id"> 
<generator strategy="AUTO"/> 
</id> 
<field name=”title” type=”string”> 
</entity> 
</doctrine­mapping>
Conventions for XML metadata 
● For MyBundleEntityArticle 
● Put XML here: 
@MyBundle/Resources/config/doctrine/ 
Article.orm.xml
We don't want it in the bundle! 
There's a nice little trick
You need DoctrineBundle >=1.2 
{ 
"require": { 
..., 
"doctrine/doctrine­bundle": 
"~1.2@dev" 
} 
}
use DoctrineBundleDoctrineBundleDependencyInjectionCompiler 
DoctrineOrmMappingsPass; 
class MyBundle extends Bundle 
{ 
public function build(ContainerBuilder $container) 
{ 
$container­> 
addCompilerPass( 
$this­> 
buildMappingCompilerPass() 
); 
} 
private function buildMappingCompilerPass() 
{ 
$xmlPath = '%kernel.root_dir%/../src/MyLibrary/Doctrine'; 
$namespacePrefix = 'MyLibraryModel'; 
return DoctrineOrmMappingsPass::createXmlMappingDriver( 
array($xmlPath => $namespacePrefix) 
); 
} 
}
Now: 
● For MyLibraryModelArticle 
● Put XML here: 
src/MyLibrary/Doctrine/Article.orm.xml
Entities - Achievements 
● Entity classes can be anywhere 
● Mapping metadata can be 
anywhere and in different formats 
● Entities are true POPOs
Finally: Templates
Conventions 
● In /Resources/views/[Controller] 
● Filename: [Action].[format].[engine]
The difficulty with templates 
They can have all kinds of implicit 
dependencies: 
● global variables, e.g. {{ app.request }} 
● functions, e.g. {{ path(...) }} 
● parent templates, e.g. {% extends 
“::base.html.twig” %}
Still, we want them out! 
And it's possible
Documentation » The Cookbook » Templating » 
How to use and Register namespaced Twig Paths 
# in config.yml 
twig: 
... 
paths: 
Twig namespaces 
"%kernel.root_dir%/../src/MyLibrary/Views": MyLibrary 
// in the controller 
return $this­> 
templating­> 
render('@MyLibrary/Template.html.twig');
Get rid of absolute paths 
Using Puli, created by Bernhard 
Schüssek (Symfony Forms, 
Validation)
What Puli does 
Find the absolute paths of 
resources in a project
use WebmozartPuliRepositoryResourceRepository; 
$repo = new ResourceRepository(); 
$repo­> 
add('/my­library/ 
views', '/absolute/path/to/views/*'); 
/my-library/views /index.html.twig 
/absolute/path/to/views /index.html.twig 
echo $repo 
­> 
get('/my­library/ 
views/index.html.twig') 
­> 
getRealPath(); 
// => /absolute/path/to/views/index.html.twig
Register “prefixes” 
Manually, or using the 
Puli Composer plugin 
// in the composer.json file of a package or project 
{ 
"extra": { 
"resources": { 
"/my­library/ 
views": "src/MyLibrary/Views" 
} 
} 
}
Twig templates 
// in composer.json 
{ 
"extra": { 
"resources": { 
"/my­library/ 
views": "src/MyLibrary/Views" 
} 
} 
} 
Puli Twig extension 
// in the controller 
return $this­> 
templating 
­> 
render('/my­library/ 
views/index.html.twig');
Many possibilities 
● Templates 
● Translation files 
●Mapping metadata 
● Service definitions 
● And so on!
The future is bright 
● Puli is not stable yet 
● But I expect much from it:
Puli will be the ultimate tool
to create NAKED BUNDLES
and to enable reuse of 
many kinds of resources
not limited by 
project, 
framework, 
even language 
boundaries!
But even without Puli 
There's a whole lot you can do to make your code 
not rely on the framework
Remember 
The framework is for you 
Your code doesn't need it
Questions?
Get a $7,50 discount: 
http://leanpub.com/a-year-with-symfony/c/SymfonyLiveLondon2014
Get a $10,00 introduction discount: 
http://leanpub.com/principles-of-php-package-design/c/SymfonyLive 
London2014
Thank you 
Feedback: joind.in/11553 
Talk to me: @matthiasnoback
Images 
Sally MacKenzie: 
www.amazon.com

More Related Content

What's hot

Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricksJavier Eguiluz
 
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?CC-Castle; The best Real-Time/Embedded/HighTech language EVER?
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?Albert Mietus
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to DomainJeremy Cook
 
ASP.Net 5 and C# 6
ASP.Net 5 and C# 6ASP.Net 5 and C# 6
ASP.Net 5 and C# 6Andy Butland
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravelwajrcs
 
MVC Demystified: Essence of Ruby on Rails
MVC Demystified: Essence of Ruby on RailsMVC Demystified: Essence of Ruby on Rails
MVC Demystified: Essence of Ruby on Railscodeinmotion
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101Samantha Geitz
 
Code Generation idioms with Xtend
Code Generation idioms with XtendCode Generation idioms with Xtend
Code Generation idioms with XtendHolger Schill
 
Ruby On Rails Tutorial
Ruby On Rails TutorialRuby On Rails Tutorial
Ruby On Rails Tutorialsunniboy
 
Apache Ant
Apache AntApache Ant
Apache AntAli Bahu
 
Symony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP FrameworkSymony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP FrameworkRyan Weaver
 
The Quest for Global Design Principles
The Quest for Global Design PrinciplesThe Quest for Global Design Principles
The Quest for Global Design PrinciplesMatthias Noback
 
JAVA EE DEVELOPMENT (JSP and Servlets)
JAVA EE DEVELOPMENT (JSP and Servlets)JAVA EE DEVELOPMENT (JSP and Servlets)
JAVA EE DEVELOPMENT (JSP and Servlets)Talha Ocakçı
 
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...Alain Hippolyte
 
JavaScript Library Overview
JavaScript Library OverviewJavaScript Library Overview
JavaScript Library Overviewjeresig
 

What's hot (20)

Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
[2015/2016] JavaScript
[2015/2016] JavaScript[2015/2016] JavaScript
[2015/2016] JavaScript
 
Ant User Guide
Ant User GuideAnt User Guide
Ant User Guide
 
Web Development with Smalltalk
Web Development with SmalltalkWeb Development with Smalltalk
Web Development with Smalltalk
 
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?CC-Castle; The best Real-Time/Embedded/HighTech language EVER?
CC-Castle; The best Real-Time/Embedded/HighTech language EVER?
 
Lecture5
Lecture5Lecture5
Lecture5
 
Beyond MVC: from Model to Domain
Beyond MVC: from Model to DomainBeyond MVC: from Model to Domain
Beyond MVC: from Model to Domain
 
ASP.Net 5 and C# 6
ASP.Net 5 and C# 6ASP.Net 5 and C# 6
ASP.Net 5 and C# 6
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravel
 
MVC Demystified: Essence of Ruby on Rails
MVC Demystified: Essence of Ruby on RailsMVC Demystified: Essence of Ruby on Rails
MVC Demystified: Essence of Ruby on Rails
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101
 
Code Generation idioms with Xtend
Code Generation idioms with XtendCode Generation idioms with Xtend
Code Generation idioms with Xtend
 
Ruby On Rails Tutorial
Ruby On Rails TutorialRuby On Rails Tutorial
Ruby On Rails Tutorial
 
Apache Ant
Apache AntApache Ant
Apache Ant
 
Symony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP FrameworkSymony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP Framework
 
The Quest for Global Design Principles
The Quest for Global Design PrinciplesThe Quest for Global Design Principles
The Quest for Global Design Principles
 
JAVA EE DEVELOPMENT (JSP and Servlets)
JAVA EE DEVELOPMENT (JSP and Servlets)JAVA EE DEVELOPMENT (JSP and Servlets)
JAVA EE DEVELOPMENT (JSP and Servlets)
 
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
 
JavaScript Library Overview
JavaScript Library OverviewJavaScript Library Overview
JavaScript Library Overview
 
Tech friday 22.01.2016
Tech friday 22.01.2016Tech friday 22.01.2016
Tech friday 22.01.2016
 

Viewers also liked

Anotaciones en Symfony. DeSymfony 2013. Ariel Ferrandini
Anotaciones en Symfony. DeSymfony 2013. Ariel FerrandiniAnotaciones en Symfony. DeSymfony 2013. Ariel Ferrandini
Anotaciones en Symfony. DeSymfony 2013. Ariel FerrandiniParadigma Digital
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsBartosz Kosarzycki
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn Cleveley
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreRyan Weaver
 
Git-flow workflow and pull-requests
Git-flow workflow and pull-requestsGit-flow workflow and pull-requests
Git-flow workflow and pull-requestsBartosz Kosarzycki
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Ryan Weaver
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014Matthias Noback
 
Symfony Best Practices
Symfony Best Practices Symfony Best Practices
Symfony Best Practices Tigran Azatyan
 

Viewers also liked (8)

Anotaciones en Symfony. DeSymfony 2013. Ariel Ferrandini
Anotaciones en Symfony. DeSymfony 2013. Ariel FerrandiniAnotaciones en Symfony. DeSymfony 2013. Ariel Ferrandini
Anotaciones en Symfony. DeSymfony 2013. Ariel Ferrandini
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
 
Git-flow workflow and pull-requests
Git-flow workflow and pull-requestsGit-flow workflow and pull-requests
Git-flow workflow and pull-requests
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
Symfony Best Practices
Symfony Best Practices Symfony Best Practices
Symfony Best Practices
 

Similar to The Naked Bundle removes Symfony conventions

The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaMatthias Noback
 
The Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumThe Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumMatthias Noback
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - TryoutMatthias Noback
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)David McCarter
 
Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019julien pauli
 
cf.Objective() 2017 - Design patterns - Brad Wood
cf.Objective() 2017 - Design patterns - Brad Woodcf.Objective() 2017 - Design patterns - Brad Wood
cf.Objective() 2017 - Design patterns - Brad WoodOrtus Solutions, Corp
 
Patterns in Python
Patterns in PythonPatterns in Python
Patterns in Pythondn
 
The Theory Of The Dom
The Theory Of The DomThe Theory Of The Dom
The Theory Of The Domkaven yan
 
Symfony finally swiped right on envvars
Symfony finally swiped right on envvarsSymfony finally swiped right on envvars
Symfony finally swiped right on envvarsSam Marley-Jarrett
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Global objects in Node.pdf
Global objects in Node.pdfGlobal objects in Node.pdf
Global objects in Node.pdfSudhanshiBakre1
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 3camp
 
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Antonio Peric-Mazar
 

Similar to The Naked Bundle removes Symfony conventions (20)

The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony Barcelona
 
The Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumThe Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup Belgium
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)Back-2-Basics: .NET Coding Standards For The Real World (2011)
Back-2-Basics: .NET Coding Standards For The Real World (2011)
 
Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019Doctrine with Symfony - SymfonyCon 2019
Doctrine with Symfony - SymfonyCon 2019
 
cf.Objective() 2017 - Design patterns - Brad Wood
cf.Objective() 2017 - Design patterns - Brad Woodcf.Objective() 2017 - Design patterns - Brad Wood
cf.Objective() 2017 - Design patterns - Brad Wood
 
Patterns in Python
Patterns in PythonPatterns in Python
Patterns in Python
 
The Theory Of The Dom
The Theory Of The DomThe Theory Of The Dom
The Theory Of The Dom
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
Symfony finally swiped right on envvars
Symfony finally swiped right on envvarsSymfony finally swiped right on envvars
Symfony finally swiped right on envvars
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Global objects in Node.pdf
Global objects in Node.pdfGlobal objects in Node.pdf
Global objects in Node.pdf
 
Java Basics
Java BasicsJava Basics
Java Basics
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
 
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
Workshop: Symfony2 Intruduction: (Controller, Routing, Model)
 

More from Matthias Noback

Rector fireside chat - PHPMiNDS meetup
Rector fireside chat - PHPMiNDS meetupRector fireside chat - PHPMiNDS meetup
Rector fireside chat - PHPMiNDS meetupMatthias Noback
 
Service abstractions - Part 1: Queries
Service abstractions - Part 1: QueriesService abstractions - Part 1: Queries
Service abstractions - Part 1: QueriesMatthias Noback
 
Hexagonal Symfony - SymfonyCon Amsterdam 2019
Hexagonal Symfony - SymfonyCon Amsterdam 2019Hexagonal Symfony - SymfonyCon Amsterdam 2019
Hexagonal Symfony - SymfonyCon Amsterdam 2019Matthias Noback
 
Advanced web application architecture - PHP Barcelona
Advanced web application architecture  - PHP BarcelonaAdvanced web application architecture  - PHP Barcelona
Advanced web application architecture - PHP BarcelonaMatthias Noback
 
A testing strategy for hexagonal applications
A testing strategy for hexagonal applicationsA testing strategy for hexagonal applications
A testing strategy for hexagonal applicationsMatthias Noback
 
Advanced web application architecture - Talk
Advanced web application architecture - TalkAdvanced web application architecture - Talk
Advanced web application architecture - TalkMatthias Noback
 
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...Matthias Noback
 
Layers, ports and adapters
Layers, ports and adaptersLayers, ports and adapters
Layers, ports and adaptersMatthias Noback
 
Beyond design principles and patterns (muCon 2019 edition)
Beyond design principles and patterns (muCon 2019 edition)Beyond design principles and patterns (muCon 2019 edition)
Beyond design principles and patterns (muCon 2019 edition)Matthias Noback
 
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Matthias Noback
 
Advanced web application architecture Way2Web
Advanced web application architecture Way2WebAdvanced web application architecture Way2Web
Advanced web application architecture Way2WebMatthias Noback
 
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Matthias Noback
 
Beyond Design Principles and Patterns
Beyond Design Principles and PatternsBeyond Design Principles and Patterns
Beyond Design Principles and PatternsMatthias Noback
 
Building Autonomous Services
Building Autonomous ServicesBuilding Autonomous Services
Building Autonomous ServicesMatthias Noback
 
Advanced Application Architecture Symfony Live Berlin 2018
Advanced Application Architecture Symfony Live Berlin 2018Advanced Application Architecture Symfony Live Berlin 2018
Advanced Application Architecture Symfony Live Berlin 2018Matthias Noback
 
Building autonomous services
Building autonomous servicesBuilding autonomous services
Building autonomous servicesMatthias Noback
 

More from Matthias Noback (20)

Rector fireside chat - PHPMiNDS meetup
Rector fireside chat - PHPMiNDS meetupRector fireside chat - PHPMiNDS meetup
Rector fireside chat - PHPMiNDS meetup
 
Service abstractions - Part 1: Queries
Service abstractions - Part 1: QueriesService abstractions - Part 1: Queries
Service abstractions - Part 1: Queries
 
Hexagonal Symfony - SymfonyCon Amsterdam 2019
Hexagonal Symfony - SymfonyCon Amsterdam 2019Hexagonal Symfony - SymfonyCon Amsterdam 2019
Hexagonal Symfony - SymfonyCon Amsterdam 2019
 
Advanced web application architecture - PHP Barcelona
Advanced web application architecture  - PHP BarcelonaAdvanced web application architecture  - PHP Barcelona
Advanced web application architecture - PHP Barcelona
 
A testing strategy for hexagonal applications
A testing strategy for hexagonal applicationsA testing strategy for hexagonal applications
A testing strategy for hexagonal applications
 
Advanced web application architecture - Talk
Advanced web application architecture - TalkAdvanced web application architecture - Talk
Advanced web application architecture - Talk
 
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
DPC 2019, Amsterdam: Beyond design patterns and principles - writing good OO ...
 
Layers, ports and adapters
Layers, ports and adaptersLayers, ports and adapters
Layers, ports and adapters
 
Beyond design principles and patterns (muCon 2019 edition)
Beyond design principles and patterns (muCon 2019 edition)Beyond design principles and patterns (muCon 2019 edition)
Beyond design principles and patterns (muCon 2019 edition)
 
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
 
Advanced web application architecture Way2Web
Advanced web application architecture Way2WebAdvanced web application architecture Way2Web
Advanced web application architecture Way2Web
 
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...Brutal refactoring, lying code, the Churn, and other emotional stories from L...
Brutal refactoring, lying code, the Churn, and other emotional stories from L...
 
Beyond Design Principles and Patterns
Beyond Design Principles and PatternsBeyond Design Principles and Patterns
Beyond Design Principles and Patterns
 
Building Autonomous Services
Building Autonomous ServicesBuilding Autonomous Services
Building Autonomous Services
 
Advanced Application Architecture Symfony Live Berlin 2018
Advanced Application Architecture Symfony Live Berlin 2018Advanced Application Architecture Symfony Live Berlin 2018
Advanced Application Architecture Symfony Live Berlin 2018
 
Designing for Autonomy
Designing for AutonomyDesigning for Autonomy
Designing for Autonomy
 
Docker workshop
Docker workshopDocker workshop
Docker workshop
 
Docker swarm workshop
Docker swarm workshopDocker swarm workshop
Docker swarm workshop
 
Docker compose workshop
Docker compose workshopDocker compose workshop
Docker compose workshop
 
Building autonomous services
Building autonomous servicesBuilding autonomous services
Building autonomous services
 

Recently uploaded

Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 

Recently uploaded (20)

Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 

The Naked Bundle removes Symfony conventions

  • 1. The Naked Bundle Matthias Noback @matthiasnoback
  • 2. What's it all about?
  • 4. I could've called it BundleLitetm The No Code Bundle The Clean Bundle
  • 5. But “naked” is catchy and controversial
  • 6. The official view on bundles
  • 7. First-class citizens Documentation » The Quick Tour » The Architecture
  • 8. Importance Your code is more important than the framework, which is an implementation detail
  • 10. Nice!
  • 11. All your code lives in a bundle Documentation » The Book » Creating Pages in Symfony2
  • 12. Reuse “All your code in a bundle” contradicts the promise of reuse
  • 13. Everything lives inside a bundle Documentation » Glossary
  • 14. Not really true Many things live inside libraries (the Symfony components are libraries too!)
  • 16. But you probably know that already
  • 18. What about... ● Controllers ● Entities ● Templates ● ...
  • 19. They just need to be in a bundle Or do they?
  • 20. Don't get me wrong I love Symfony!
  • 21. But a framework is just a framework ● Quickstarter for your projects ● Prevents and solves big security issues for you ● Has a community you can rely on
  • 22. A framework is there for you
  • 23. Your code doesn't need a framework
  • 24. Noback's Principle Code shouldn't rely on something it doesn't truly need
  • 25. Bundle conventions Things in a bundle often rely on conventions to work
  • 27. So according to Noback's Principle, code shouldn't rely on bundle conventions too
  • 28. Naming conventions Controllers: ● *Controller classes ● *action methods Templates: ● in /Resources/views ● name: Controller/Action.html.twig
  • 29. Structural conventions Controller: ● Extends framework Controller class ● Is ContainerAware
  • 30. Behavioral conventions Controller: ● Is allowed to return an array ● Actions can type-hint to objects which will be fetched based on route parameters (??)
  • 31. Configuration conventions Use lots of annotations! /** * @Route("/{id}") * @Method("GET") * @ParamConverter("post", class="SensioBlogBundle:Post") * @Template("SensioBlogBundle:Annot:show.html.twig") * @Cache(smaxage="15", lastmodified="post.getUpdatedAt()") * @Security("has_role('ROLE_ADMIN')") */ public function showAction(Post $post) { }
  • 32. These conventions are what makes an application a Symfony2 application
  • 33. A Year With Symfony
  • 35. A bundle exposes resources
  • 36. Resources ● Service definitions ● Controllers ● Routes ● Templates ● Entities ● Form types ● Event listeners ● Translations ● ...
  • 37. No need for them to be inside a bundle
  • 38. When placed outside the bundle the resources could be reused separately
  • 39. The bundle would be really small
  • 40. And could just as well be a: Laravel package, Zend or Drupal module, CakePHP plugin, ...
  • 41. So the challenge is to Make the bundle as clean as possible
  • 42. Move the “misplaced” things to ● a library ● with dependencies ● but not symfony/framework­bundle ;)
  • 44. Reuse within the Symfony family Think: Silex, Laravel, etc.
  • 45. Allowed dependency HttpFoundation ● Request ● Response ● Exceptions ● etc.
  • 46. What do we rely on HttpKernel namespace SymfonyComponentHttpKernel; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; interface HttpKernelInterface { /** * Handles a Request to convert it to a Response. */ public function handle(Request $request, ...); }
  • 47. Why? My secret missions “Let's rebuild the application, but this time we use Zend4 instead of Symfony2”
  • 48. And of course Education
  • 49. You need a strong coupling radar
  • 50. Explicit dependencies ● Function calls ● Imported classes (“use”) ● Included files ● ...
  • 51. Implicit dependencies ● File locations ● File, class, method names ● Structure of return values ● ...
  • 53. use SymfonyBundleFrameworkBundleControllerController; use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationTemplate; /** * @Route(“/article”) */ class ArticleController extends Controller { /** * @Route(“/edit”) * @Template() */ function editAction(...) { ... } } Controller
  • 54. TODO ✔ Don't rely on things that may not be there in another context: ✔ Parent Controller class ✔ Routing, template, annotations, etc.
  • 55. class ArticleController { function editAction(...) { ... } } Nice and clean ;)
  • 56. use SymfonyComponentHttpFoundationRequest; class ArticleController { public function editAction(Request $request) { $em = $this­> get('doctrine')­> getManager(); ... if (...) { throw $this­> createNotFoundException(); } ... return array( 'form' => $form­> createView() ); } } Zooming in a bit
  • 57. TODO ✔ Inject dependencies ✔ Don't use helper methods ✔ Render the template manually ✔ Keep using Request (not really a TODO)
  • 58. use DoctrineORMEntityManager; class ArticleController { function __construct( EntityManager $em, ) { $this­> em = $em; } ... } Inject dependencies
  • 59. Inline helper methods use SymfonyComponentHttpKernelExceptionNotFoundHttpException class ArticleController { ... public function newAction(...) { ... throw new NotFoundHttpException(); ... } }
  • 60. use SymfonyComponentHttpFoundationResponse; use SymfonyComponentTemplatingEngineInterface; class ArticleController { function __construct(..., EngineInterface $templating) { } public function newAction(...) { ... return new Response( $this­> templating­> render( '@MyBundle:Article:new.html.twig', array( 'form' => $form­> createView() ) ) ); } } Render the template manually
  • 61. Dependencies are explicit now Also: no mention of a “bundle” anywhere! use SymfonyComponentHttpFoundationRequest; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentTemplatingEngineInterface; use DoctrineORMEntityManager;
  • 62. Dependency overflow use SymfonyComponentHttpFoundationResponse; use SymfonyComponentTemplatingEngineInterface; class ArticleController { function __construct( EntityManager $entityManager, EngineInterface $templating, TranslatorInterface $translator, ValidatorInterface $validator, Swift_Mailer $mailer, RouterInterface $router ) { ... } ... }
  • 64. One controller, many actions one action!
  • 65. __invoke() namespace MyLibraryControllerArticle; class New { function __construct(...) { // only what's necessary for this “action” } public function __invoke(...) { ... } }
  • 66. Nice! └─Controller └─Article ├─New.php ├─Edit.php ├─Archive.php └─Delete.php
  • 67. TODO ✔ Set up routing ✔ Create a service and provide the right arguments
  • 68. Bundle stuff: services.xml <!­­in MyBundle/Resources/config/services.xml → <?xml version="1.0" ?> <container> <services> <service id="new_article_controller" class="MyBundleControllerArticleNew"> <argument type="service" id="doctrine.orm.default_entity_manager" /> <argument type="service" id="templating" /> </service> </services> </container>
  • 69. Bundle stuff: routing.xml <!­­in MyBundle/Resources/config/routing.xml → <?xml version="1.0" encoding="UTF­8" ?> <routes> <route id="new_article" path="/article/new"> <default key="_controller"> new_article_controller:__invoke </default> </route> </routes> Pull request by Kevin Bond allows you to leave out the “:__invoke” part!
  • 70. Controller – Achievements ● Can be anywhere ● No need to follow naming conventions (“*Controller”, “*action”) ● Dependency injection, no service location ● Reusable in any application using HttpFoundation
  • 72. namespace MyBundleEntity; use DoctrineORMMapping as ORM; class Article { ... /** * @ORMColumn(type=”string”) */ private $title; } Entity conventions
  • 73. What's wrong with annotations? namespace MyBundleEntity; use DoctrineORMMapping as ORM; class Article { ... /** * @ORMColumn(type=”string”) */ private $title; }
  • 75. use DoctrineCommonAnnotationsAnnotationReader; $reader = new AnnotationReader(); $class = new ReflectionClass('Article'); $reader­> getClassAnnotations($class); BANG Class DoctrineORMMappingColumn not found
  • 76. Well, uhm, yes, but...
  • 77. Are you ever going to use anything else than Doctrine ORM?
  • 78. Well... Think about Doctrine MongoDB ODM, Doctrine CouchDB ODM, etc. namespace MyBundleEntity; use DoctrineORMMapping as ORM; use DoctrineODMMongoDBMappingAnnotations as MongoDB; use DoctrineODMCouchDBMappingAnnotations as CoucheDB; class Article { /** * @ORMColumn * @MognoDBField * @CoucheDBField */ private $title; }
  • 79. TODO ✔ Remove annotations ✔ Find another way to map the data
  • 80. namespace MyBundleEntity; class Article { private $id; private $title; } Nice and clean A true POPO, the ideal of the data mapper pattern
  • 81. Use XML for mapping metadata <doctrine­mapping> <entity name=”MyBundleEntityArticle”> <id name="id" type="integer" column="id"> <generator strategy="AUTO"/> </id> <field name=”title” type=”string”> </entity> </doctrine­mapping>
  • 82. Conventions for XML metadata ● For MyBundleEntityArticle ● Put XML here: @MyBundle/Resources/config/doctrine/ Article.orm.xml
  • 83. We don't want it in the bundle! There's a nice little trick
  • 84. You need DoctrineBundle >=1.2 { "require": { ..., "doctrine/doctrine­bundle": "~1.2@dev" } }
  • 85. use DoctrineBundleDoctrineBundleDependencyInjectionCompiler DoctrineOrmMappingsPass; class MyBundle extends Bundle { public function build(ContainerBuilder $container) { $container­> addCompilerPass( $this­> buildMappingCompilerPass() ); } private function buildMappingCompilerPass() { $xmlPath = '%kernel.root_dir%/../src/MyLibrary/Doctrine'; $namespacePrefix = 'MyLibraryModel'; return DoctrineOrmMappingsPass::createXmlMappingDriver( array($xmlPath => $namespacePrefix) ); } }
  • 86. Now: ● For MyLibraryModelArticle ● Put XML here: src/MyLibrary/Doctrine/Article.orm.xml
  • 87. Entities - Achievements ● Entity classes can be anywhere ● Mapping metadata can be anywhere and in different formats ● Entities are true POPOs
  • 89. Conventions ● In /Resources/views/[Controller] ● Filename: [Action].[format].[engine]
  • 90. The difficulty with templates They can have all kinds of implicit dependencies: ● global variables, e.g. {{ app.request }} ● functions, e.g. {{ path(...) }} ● parent templates, e.g. {% extends “::base.html.twig” %}
  • 91. Still, we want them out! And it's possible
  • 92. Documentation » The Cookbook » Templating » How to use and Register namespaced Twig Paths # in config.yml twig: ... paths: Twig namespaces "%kernel.root_dir%/../src/MyLibrary/Views": MyLibrary // in the controller return $this­> templating­> render('@MyLibrary/Template.html.twig');
  • 93. Get rid of absolute paths Using Puli, created by Bernhard Schüssek (Symfony Forms, Validation)
  • 94. What Puli does Find the absolute paths of resources in a project
  • 95. use WebmozartPuliRepositoryResourceRepository; $repo = new ResourceRepository(); $repo­> add('/my­library/ views', '/absolute/path/to/views/*'); /my-library/views /index.html.twig /absolute/path/to/views /index.html.twig echo $repo ­> get('/my­library/ views/index.html.twig') ­> getRealPath(); // => /absolute/path/to/views/index.html.twig
  • 96. Register “prefixes” Manually, or using the Puli Composer plugin // in the composer.json file of a package or project { "extra": { "resources": { "/my­library/ views": "src/MyLibrary/Views" } } }
  • 97. Twig templates // in composer.json { "extra": { "resources": { "/my­library/ views": "src/MyLibrary/Views" } } } Puli Twig extension // in the controller return $this­> templating ­> render('/my­library/ views/index.html.twig');
  • 98. Many possibilities ● Templates ● Translation files ●Mapping metadata ● Service definitions ● And so on!
  • 99. The future is bright ● Puli is not stable yet ● But I expect much from it:
  • 100. Puli will be the ultimate tool
  • 101. to create NAKED BUNDLES
  • 102. and to enable reuse of many kinds of resources
  • 103. not limited by project, framework, even language boundaries!
  • 104. But even without Puli There's a whole lot you can do to make your code not rely on the framework
  • 105. Remember The framework is for you Your code doesn't need it
  • 107. Get a $7,50 discount: http://leanpub.com/a-year-with-symfony/c/SymfonyLiveLondon2014
  • 108. Get a $10,00 introduction discount: http://leanpub.com/principles-of-php-package-design/c/SymfonyLive London2014
  • 109. Thank you Feedback: joind.in/11553 Talk to me: @matthiasnoback
  • 110. Images Sally MacKenzie: www.amazon.com