symfony cookbook 2.6

Download Symfony Cookbook 2.6

If you can't read please download the document

Upload: visi-hoxha

Post on 24-Dec-2015

237 views

Category:

Documents


9 download

TRANSCRIPT

  • The CookbookVersion: 2.6

    generated on March 3, 2015

  • The Cookbook (2.6)

    This work is licensedunder the Attribution-Share Alike 3.0 Unported license(http://creativecommons.org/licenses/by-sa/3.0/).

    You arefreeto share (to copy,distribute and transmit the work), and to remix (to adaptthe work) under thefollowing conditions:

    Attribution : You must attribute the work in the mannerspecifiedby the author or licensor (butnot in any way that suggests that they endorse you or your use of the work).

    ShareAlike : If you alter, transform,or build upon this work, you maydistribute the resultingworkonly under the same,similar or a compatiblelicense.For any reuseor distribution, you must makeclear to others the license terms of this work.

    The information in this book is distributed on an as is basis,without warranty. Although everyprecautionhasbeentaken in the preparationof this work, neither the author(s)nor SensioLabsshallhaveany liability toanypersonor entity with respectto any lossor damagecausedor allegedto becauseddirectly or indirectly bythe information contained in this work.

    If you find typos or errors, feel free to report them by creating a ticket on the Symfony ticketing system(http://github.com/symfony/symfony-docs/issues). Based on tickets and users feedback, this book iscontinuously updated.

  • Contents at a Glance

    How to Use Assetic for Asset Management..........................................................................................7How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS)...............................................................13How to Minify JavaScripts and Stylesheets with YUI Compressor.......................................................17How to Use Assetic for Image Optimization with Twig Functions......................................................20How to Apply an Assetic Filter to a specific File Extension.................................................................22How to Install 3rd Party Bundles.......................................................................................................24Best Practices for Reusable Bundles...................................................................................................27How to Use Bundle Inheritance to Override Parts of a Bundle............................................................34How to Override any Part of a Bundle...............................................................................................36How to Remove the AcmeDemoBundle.............................................................................................39How to Load Service Configuration inside a Bundle...........................................................................42How to Create Friendly Configuration for a Bundle...........................................................................45How to Simplify Configuration of multiple Bundles...........................................................................51How to Use Varnish to Speed up my Website....................................................................................54Caching Pages that Contain CSRF Protected Forms...........................................................................58Installing Composer..........................................................................................................................59How to Master and Create new Environments...................................................................................61How to Override Symfonys default Directory Structure.....................................................................66Using Parameters within a Dependency Injection Class......................................................................70Understanding how the Front Controller, Kernel and Environments Work together............................73How to Set external Parameters in the Service Container....................................................................76How to Use PdoSessionHandler to Store Sessions in the Database......................................................79How to Use the Apache Router.........................................................................................................83Configuring a Web Server.................................................................................................................86How to Organize Configuration Files................................................................................................91How to Create a Console Command.................................................................................................96How to Use the Console..................................................................................................................101How to Generate URLs and Send Emails from the Console..............................................................103How to Enable Logging in Console Commands...............................................................................105How to Define Commands as Services.............................................................................................109How to Customize Error Pages........................................................................................................111How to Define Controllers as Services.............................................................................................116How to Optimize your Development Environment for Debugging....................................................120How to Deploy a Symfony Application............................................................................................122Deploying to Microsoft Azure Website Cloud..................................................................................126Deploying to Heroku Cloud............................................................................................................139

    PDF brought to you bygenerated on March 3, 2015

    Contents at a Glance | iii

    http://sensiolabs.com
  • Deploying to Platform.sh.................................................................................................................143How to Handle File Uploads with Doctrine.....................................................................................147How to use Doctrine Extensions: Timestampable, Sluggable, Translatable, etc.................................156How to Register Event Listeners and Subscribers.............................................................................157How to Use Doctrine DBAL............................................................................................................160How to Generate Entities from an Existing Database........................................................................162How to Work with multiple Entity Managers and Connections........................................................166How to Register custom DQL Functions..........................................................................................169How to Define Relationships with Abstract Classes and Interfaces....................................................170How to Provide Model Classes for several Doctrine Implementations...............................................173How to Implement a simple Registration Form................................................................................177Console Commands........................................................................................................................183How to Send an Email.....................................................................................................................184How to Use Gmail to Send Emails...................................................................................................187How to Use the Cloud to Send Emails.............................................................................................188How to Work with Emails during Development...............................................................................190How to Spool Emails.......................................................................................................................193How to Test that an Email is Sent in a functional Test......................................................................195How to Setup before and after Filters...............................................................................................197How to Extend a Class without Using Inheritance............................................................................201How to Customize a Method Behavior without Using Inheritance....................................................204How to use Expressions in Security, Routing, Services, and Validation.............................................206How to Customize Form Rendering................................................................................................209How to Use Data Transformers.......................................................................................................222How to Dynamically Modify Forms Using Form Events...................................................................229How to Embed a Collection of Forms..............................................................................................241How to Create a Custom Form Field Type.......................................................................................254How to Create a Form Type Extension............................................................................................259How to Reduce Code Duplication with "inherit_data".....................................................................264How to Unit Test your Forms..........................................................................................................268How to Configure empty Data for a Form Class...............................................................................273How to Use the submit() Function to Handle Form Submissions......................................................275How to Use the virtual Form Field Option.......................................................................................278How to Use Monolog to Write Logs................................................................................................279How to Configure Monolog to Email Errors....................................................................................283How to Configure Monolog to Display Console Messages................................................................285How to Configure Monolog to Exclude 404 Errors from the Log......................................................287How to Log Messages to different Files............................................................................................288How to Create a custom Data Collector...........................................................................................290How to Use Matchers to Enable the Profiler Conditionally...............................................................293Switching the Profiler Storage..........................................................................................................296How to Configure Symfony to Work behind a Load Balancer or a Reverse Proxy..............................297How to Register a new Request Format and Mime Type...................................................................299How to Force Routes to always Use HTTPS or HTTP......................................................................301How to Allow a "/" Character in a Route Parameter.........................................................................302How to Configure a Redirect without a custom Controller...............................................................303How to Use HTTP Methods beyond GET and POST in Routes........................................................305

    iv | Contents at a Glance Contents at a Glance | 4

  • How to Use Service Container Parameters in your Routes................................................................307How to Create a custom Route Loader............................................................................................309Redirect URLs with a Trailing Slash.................................................................................................313How to Pass Extra Information from a Route to a Controller............................................................315How to Build a Traditional Login Form...........................................................................................316How to Load Security Users from the Database (the Entity Provider)................................................321How to Add "Remember Me" Login Functionality...........................................................................334How to Impersonate a User.............................................................................................................337How to Implement your own Voter to Blacklist IP Addresses...........................................................339How to Use Voters to Check User Permissions.................................................................................342How to Use Access Control Lists (ACLs).........................................................................................347How to Use advanced ACL Concepts..............................................................................................351How to Force HTTPS or HTTP for different URLs...........................................................................355How to Restrict Firewalls to a Specific Request................................................................................356How to Restrict Firewalls to a Specific Host.....................................................................................358How to Customize your Form Login................................................................................................359How to Secure any Service or Method in your Application...............................................................362How to Create a custom User Provider............................................................................................366How to Create a Custom Form Password Authenticator...................................................................371How to Authenticate Users with API Keys.......................................................................................375How to Create a custom Authentication Provider.............................................................................384Using pre Authenticated Security Firewalls......................................................................................393How to Change the default Target Path Behavior.............................................................................395Using CSRF Protection in the Login Form........................................................................................397How to Choose the Password Encoder Algorithm Dynamically........................................................399How Does the Security access_control Work?..................................................................................401How to Use multiple User Providers................................................................................................405How to Use the Serializer................................................................................................................407How to Create an Event Listener.....................................................................................................409How to Work with Scopes..............................................................................................................412How to Work with Compiler Passes in Bundles...............................................................................417Session Proxy Examples..................................................................................................................418Making the Locale "Sticky" during a Users Session..........................................................................420Configuring the Directory where Session Files are Saved..................................................................422Bridge a legacy Application with Symfony Sessions..........................................................................424Limit Session Metadata Writes........................................................................................................426Avoid Starting Sessions for Anonymous Users..................................................................................427How Symfony2 Differs from Symfony1............................................................................................428How to Inject Variables into all Templates (i.e. global Variables)......................................................433How to Use and Register Namespaced Twig Paths...........................................................................435How to Use PHP instead of Twig for Templates...............................................................................437How to Write a custom Twig Extension..........................................................................................443How to Render a Template without a custom Controller..................................................................446How to Simulate HTTP Authentication in a Functional Test............................................................448How to Simulate Authentication with a Token in a Functional Test..................................................449How to Test the Interaction of several Clients..................................................................................451How to Use the Profiler in a Functional Test....................................................................................453

    PDF brought to you bygenerated on March 3, 2015

    Contents at a Glance | v

    http://sensiolabs.com
  • How to Test Code that Interacts with the Database..........................................................................455How to Test Doctrine Repositories..................................................................................................458How to Customize the Bootstrap Process before Running Tests........................................................460How to Upgrade Your Symfony Project...........................................................................................462How to Create a custom Validation Constraint................................................................................465How to Use PHPs built-in Web Server............................................................................................469How to Create a SOAP Web Service in a Symfony Controller...........................................................472How to Create and Store a Symfony Project in Git...........................................................................476How to Create and Store a Symfony Project in Subversion................................................................479

    vi | Contents at a Glance Contents at a Glance | 6

  • Listing 1-1

    Listing 1-2

    Chapter 1

    How to Use Assetic for Asset Management

    Asseticcombinestwo major ideas:assetsand filters. TheassetsarefilessuchasCSS,JavaScriptand imagefiles. The filters are things that can be applied to thesefiles beforethey areservedto the browser.Thisallowsa separationbetweenthe assetfilesstoredin the applicationand the filesactuallypresentedto theuser.

    Without Assetic, you just serve the files that are stored in the application directly:

    1

    But with Assetic,you canmanipulatetheseassetshoweveryou want (or load them from anywhere)beforeserving them. This means you can:

    Minify and combine all of your CSS and JS files Run all (or just some)of your CSSor JSfiles through somesort of compiler, such asLESS,

    SASS or CoffeeScript Run image optimizations on your images

    AssetsUsingAsseticprovidesmanyadvantagesoverdirectly servingthe files.The filesdo not needto bestoredwhere they are served from and can be drawn from various sources such as from within a bundle.

    You canuseAsseticto processCSSstylesheets, JavaScriptfilesand images. Thephilosophybehindaddingeither is basically the same, but with a slightly different syntax.

    Including JavaScript Files

    To include JavaScript files, use thejavascripts tag in any template:

    123

    {% javascripts @AppBundle/Resources/public/js/* %}

    {% endjavascripts %}

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 7

    http://sensiolabs.com
  • Listing 1-3

    Listing 1-4

    Listing 1-5

    Listing 1-6

    If youreusing the default block namesfrom the SymfonyStandardEdition, the javascripts tagwill most commonly live in thejavascripts block:

    1234567

    {# ... #}{% block javascripts %}

    {% javascripts @AppBundle/Resources/public/js/* %}

    {% endjavascripts %}{% endblock %}{# ... #}

    You can also include CSS Stylesheets: seeIncluding CSS Stylesheets.

    In this example,all of the files in the Resources/public/ js/ directory of the AppBundlewill be loadedand served from a different location. The actual rendered tag might simply look like:

    1

    This is a key point: onceyou let Assetichandleyour assets,the files areservedfrom a different location.This will causeproblemswith CSSfiles that referenceimagesby their relativepath. SeeFixingCSSPathswith the cssrewrite Filter.

    Including CSS Stylesheets

    To bring in CSS stylesheets,you can use the same methodologies seen above, except with thestylesheets tag:

    123

    {% stylesheets bundles/app/css/* filter =cssrewrite %}

    {% endstylesheets %}

    If youreusing the default block namesfrom the SymfonyStandardEdition, the stylesheets tagwill most commonly live in thestylesheets block:

    1234567

    {# ... #}{% block stylesheets %}

    {% stylesheets bundles/app/css/* filter =cssrewrite %}

    {% endstylesheets %}{% endblock %}{# ... #}

    But becauseAsseticchangesthe paths to your assets,this will break any background images(or otherpaths) that uses relative paths, unless you use thecssrewritefilter.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 8

    http://sensiolabs.com
  • Listing 1-7

    Listing 1-8

    Notice that in the original examplethat included JavaScriptfiles, you referredto the files usingapath like @AppBundle/Resources/public/ file.js , but that in this example,you referredto theCSSfilesusingtheir actual,publicly-accessiblepath: bundles/ app/css. You canuseeither,exceptthat there is a known issuethat causesthe cssrewrite filter to fail when using the @AppBundlesyntax for CSS Stylesheets.

    Including Images

    To include an image you can use theimagetag.

    123

    {% image @AppBundle/Resources/public/images/example.jpg %}

    {% endimage%}

    You can also use Asseticfor imageoptimization. More information in How to UseAsseticfor ImageOptimization with Twig Functions.

    Fixing CSS Paths with thecssrewrite Filter

    SinceAsseticgeneratesnew URLs for your assets,any relativepaths insideyour CSSfiles will break.Tofix this, makesure to usethe cssrewrite filter with your stylesheets tag. This parsesyour CSSfilesand corrects the paths internally to reflect the new location.

    You can see an example in the previous section.

    When using the cssrewrite filter, dont refer to your CSSfiles using the @AppBundlesyntax.Seethe note in the above section for details.

    Combining Assets

    One featureof Asseticis that it will combine many files into one. This helps to reducethe number ofHTTP requests,which is great for front end performance.It alsoallows you to maintain the files moreeasilyby splitting them into manageableparts. This can help with re-usability as you can easilysplitproject-specificfiles from thosewhich canbe usedin other applications,but still servethem asa singlefile:

    123456

    {% javascripts@AppBundle/Resources/public/js/*@AcmeBarBundle/Resources/public/js/form.js@AcmeBarBundle/Resources/public/js/calendar.js %}

    {% endjavascripts %}

    In the devenvironment,eachfile is still servedindividually, so that you candebugproblemsmoreeasily.However, in the prod environment (or more specifically,when the debug flag is false ), this will berendered as a singlescript tag, which contains the contents of all of the JavaScript files.

    If youre new to Asseticand try to useyour application in the prod environment (by using theapp.php controller), youll likely seethat all of your CSSand JSbreaks.Dont worry! This is onpurpose. For details on using Assetic in theprod environment, seeDumping Asset Files.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 9

    http://sensiolabs.com
  • Listing 1-9

    Listing 1-10

    Listing 1-11

    Listing 1-12

    And combining files doesntonly apply to your files. You can also useAsseticto combine third partyassets, such as jQuery, with your own into a single file:

    12345

    {% javascripts@AppBundle/Resources/public/js/thirdparty/jquery.js@AppBundle/Resources/public/js/* %}

    {% endjavascripts %}

    Using Named Assets

    AsseticBundleconfiguration directivesallow you to definenamedassetsets.You cando so by definingthe input files, filters andoutput files in your configurationunder the assetic section.Readmore in theassetic config reference.

    1234567

    # app/config/config.ymlassetic :

    assets :jquery_and_ui :

    inputs :- @AppBundle/Resources/public/js/thirdparty/jquery.js- @AppBundle/Resources/public/js/thirdparty/jquery.ui.js

    After you have defined the named assets,you can reference them in your templates with the@named_assetnotation:

    12345

    {% javascripts@jquery_and_ui@AppBundle/Resources/public/js/* %}

    {% endjavascripts %}

    FiltersOncetheyremanagedby Assetic,you canapply filters to your assetsbeforetheyareserved.This includesfilters that compressthe output of your assetsfor smallerfile sizes(and better front-end optimization).Other filters cancompileJavaScriptfile from CoffeeScriptfilesandprocessSASSinto CSS.In fact,Assetichas a long list of available filters.

    Many of the filters do not do the work directly, but useexisting third-party libraries to do the heavy-lifting. This meansthat youll often needto install a third-party library to usea filter. Thegreatadvantageof usingAsseticto invoke theselibraries (asopposedto using them directly) is that insteadof having torun them manuallyafteryou work on the files,Asseticwill takecareof this for you and removethis stepaltogether from your development and deployment processes.

    To usea filter, you first needto specifyit in the Asseticconfiguration. Adding a filter heredoesntmeanits being used - it just means that its available to use (youll use the filter below).

    For example to use the UglifyJS JavaScript minifier the following config should be added:

    123

    # app/config/config.ymlassetic :

    filters :

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 10

    http://sensiolabs.com
  • Listing 1-13

    Listing 1-14

    Listing 1-15

    45

    uglifyjs2 :bin : /usr/local/bin/uglifyjs

    Now, to actuallyusethe filter on a group of JavaScript files, add it into your template:

    123

    {% javascripts @AppBundle/Resources/public/js/* filter =uglifyjs2 %}

    {% endjavascripts %}

    A more detailed guide about configuring and using Asseticfilters as well as details of Asseticsdebugmode can be found inHow to Minify CSS/JS Files (Using UglifyJS and UglifyCSS).

    Controlling the URL UsedIf you wish to, you can control the URLs that Asseticproduces.This is done from the templateand isrelative to the public document root:

    123

    {% javascripts @AppBundle/Resources/public/js/* output =js/compiled/main.js %}

    {% endjavascripts %}

    Symfony also contains a method for cachebusting, where the final URL generatedby Asseticcontainsa query parameterthat can be incrementedvia configuration on eachdeployment.Formore information, see theassets_versionconfiguration option.

    Dumping Asset FilesIn the dev environment,Asseticgeneratespathsto CSSand JavaScriptfiles that dont physicallyexistonyour computer.But they rendernonethelessbecausean internal Symfonycontroller opensthe files andserves back the content (after running any filters).

    This kind of dynamicservingof processedassetsis greatbecauseit meansthat you can immediatelyseethe newstateof anyassetfilesyou change.Its alsobad,becauseit canbequite slow. If youreusinga lotof filters, it might be downright frustrating.

    Fortunately, Assetic provides a way to dump your assetsto real files, instead of being generateddynamically.

    Dumping Asset Files in theprod Environment

    In the prod environment, your JSand CSSfiles are representedby a single tag each. In other words,insteadof seeingeachJavaScriptfile youre including in your source,youll likely just seesomethinglikethis:

    1

    Moreover, that file doesnot actuallyexist, nor is it dynamicallyrenderedby Symfony(as the assetfilesare in the dev environment).This is on purpose- letting Symfonygeneratethesefiles dynamically in aproduction environment is just too slow.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 11

    http://sensiolabs.com
  • Listing 1-16

    Listing 1-17

    Listing 1-18

    Listing 1-19

    Listing 1-20

    Instead,eachtime you useyour app in the prod environment(and therefore,eachtime you deploy),youshould run the following task:

    1 $ php app/console assetic:dump --env =prod --no-debug

    This will physicallygenerateand write eachfile that you need(e.g./js/ abcd123.js ). If you updateanyof your assets, youll need to run this again to regenerate the file.

    Dumping Asset Files in thedevEnvironment

    By default, eachassetpath generatedin the dev environment is handleddynamicallyby Symfony.Thishasno disadvantage(you canseeyour changesimmediately),exceptthat assetscanloadnoticeablyslow.If you feel like your assets are loading too slowly, follow this guide.

    First, tell Symfonyto stop trying to processthesefiles dynamically.Make the following changein yourconfig_dev.yml file:

    123

    # app/config/config_dev.ymlassetic :

    use_controller : false

    Next, sinceSymfonyis no longergeneratingtheseassetsfor you, youll needto dump them manually.Todo so, run the following:

    1 $ php app/console assetic:dump

    This physically writes all of the assetfiles you need for your dev environment. The big disadvantageis that you need to run this eachtime you update an asset.Fortunately, by using the assetic:watchcommand, assets will be regenerated automaticallyas they change:

    1 $ php app/console assetic:watch

    Theassetic:watch commandwasintroduced in AsseticBundle2.4. In prior versions,you had to usethe--watch option of theassetic:dump command for the same behavior.

    Sincerunning this command in the dev environmentmay generatea bunch of files, its usually a goodidea to point your generatedassetfiles to some isolateddirectory (e.g. /js/ compiled), to keep thingsorganized:

    123

    {% javascripts @AppBundle/Resources/public/js/* output =js/compiled/main.js %}

    {% endjavascripts %}

    PDF brought to you bygenerated on March 3, 2015

    Chapter 1: How to Use Assetic for Asset Management | 12

    http://sensiolabs.com
  • Listing 2-1

    Chapter 2

    How to Minify CSS/JS Files (Using UglifyJS andUglifyCSS)

    UglifyJS1 is a JavaScriptparser/compressor/beautifier toolkit. It can be used to combine and minifyJavaScriptassetsso that they require lessHTTP requestsand makeyour site load faster.UglifyCSS2 is aCSS compressor/beautifier that is very similar to UglifyJS.

    In this cookbook, the installation, configuration and usageof UglifyJS is shown in detail. UglifyCSSworks pretty much the same way and is only talked about briefly.

    Install UglifyJSUglifyJSis availableasanNode.js3 npm moduleandcanbe installedusingnpm. First, you needto installNode.js4. Afterwards you can install UglifyJS using npm:

    1 $ npm install -g uglify-js

    This command will install UglifyJS globally and you may need to run it as a root user.

    1. https://github.com/mishoo/UglifyJS

    2. https://github.com/fmarcia/UglifyCSS

    3. http://nodejs.org/

    4. http://nodejs.org/

    PDF brought to you bygenerated on March 3, 2015

    Chapter 2: How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) | 13

    http://sensiolabs.com
  • Listing 2-2

    Listing 2-3

    Listing 2-4

    Listing 2-5

    Listing 2-6

    Its alsopossibleto install UglifyJSinside your project only. To do this, install it without the -goption and specify the path where to put the module:

    123

    $ cd /path/to/symfony$ mkdir app/Resources/node_modules$ npm install uglify-js --prefix app/Resources

    It is recommended that you install UglifyJS in your app/Resources folder and add thenode_modulesfolder to versioncontrol. Alternatively,you cancreateannpm package.json5 file andspecify your dependencies there.

    Dependingon your installation method, you should either be able to executethe uglifyjs executableglobally, or execute the physical file that lives in thenode_modulesdirectory:

    123

    $ uglifyjs --help

    $ ./app/Resources/node_modules/.bin/uglifyjs --help

    Configure theuglifyjs2 FilterNow we need to configure Symfony to use theuglifyjs2 filter when processing your JavaScripts:

    123456

    # app/config/config.ymlassetic :

    filters :uglifyjs2 :

    # the path to the uglifyjs executablebin : /usr/local/bin/uglifyjs

    The path whereUglifyJSis installedmayvary dependingon your system.To find out wherenpmstores thebin folder, you can use the following command:

    1 $ npm bin -g

    It should output a folder on your system, inside which you should find the UglifyJS executable.

    If you installed UglifyJSlocally, you can find the bin folder inside the node_modulesfolder. Itscalled.bin in this case.

    You now have access to theuglifyjs2 filter in your application.

    Configure thenodeBinaryAssetictries to find the node binary automatically. If it cannot be found, you canconfigure its locationusing thenodekey:

    5. http://package.json.nodejitsu.com/

    PDF brought to you bygenerated on March 3, 2015

    Chapter 2: How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) | 14

    http://sensiolabs.com
  • Listing 2-7

    Listing 2-8

    12345678

    # app/config/config.ymlassetic :

    # the path to the node executablenode: /usr/bin/nodejsfilters :

    uglifyjs2 :# the path to the uglifyjs executablebin : /usr/local/bin/uglifyjs

    Minify your AssetsIn order to useUglifyJSon your assets,you needto apply it to them. Sinceyour assetsarea part of theview layer, this work is done in your templates:

    123

    {% javascripts @AppBundle/Resources/public/js/* filter =uglifyjs2 %}

    {% endjavascripts %}

    Theaboveexampleassumesthat you haveabundlecalledAppBundleandyour JavaScriptfilesarein the Resources/public/ js directory underyour bundle.This isnt important however- you caninclude your JavaScript files no matter where they are.

    With theaddition of theuglifyjs2 filter to theassettagsabove,you shouldnow seeminified JavaScriptscoming over the wire much faster.

    Disable Minification in Debug Mode

    Minified JavaScriptsareverydifficult to read, let alonedebug.Becauseof this, Asseticletsyou disableacertain filter when your application is in debug(e.g.app_dev.php) mode.You can do this by prefixingthe filter namein your templatewith a questionmark: ?. This tells Asseticto only apply this filter whendebug mode is off (e.g.app.php):

    123

    {% javascripts @AppBundle/Resources/public/js/* filter =?uglifyjs2 %}

    {% endjavascripts %}

    To try this out, switch to your prod environment(app.php). But beforeyou do, dont forget to clearyourcacheanddump your assetic assets.

    Insteadof addingthe filter to the assettags,you canalsogloballyenableit by addingthe apply_toattribute to the filter configuration, for examplein the uglifyjs2 filter apply_to: "\.js$" . Toonly havethe filter appliedin production, add this to theconfig_prod file rather than thecommonconfig file. For details on applying filters by file extension, seeFiltering Based on a File Extension.

    Install, Configure and Use UglifyCSSThe usage of UglifyCSS works the same way as UglifyJS. First, make sure the node package is installed:

    PDF brought to you bygenerated on March 3, 2015

    Chapter 2: How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) | 15

    http://sensiolabs.com
  • Listing 2-9

    Listing 2-10

    Listing 2-11

    1 $ npm install -g uglifycss

    Next, add the configuration for this filter:

    12345

    # app/config/config.ymlassetic :

    filters :uglifycss :

    bin : /usr/local/bin/uglifycss

    To use the filter for your CSS files, add the filter to the Asseticstylesheets helper:

    123

    {% stylesheets bundles/App/css/* filter =uglifycss filter =cssrewrite %}

    {% endstylesheets %}

    Justlike with the uglifyjs2 filter, if you prefix the filter namewith ? (i.e. ?uglifycss ), the minificationwill only happen when youre not in debug mode.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 2: How to Minify CSS/JS Files (Using UglifyJS and UglifyCSS) | 16

    http://sensiolabs.com
  • Listing 3-1

    Chapter 3

    How to Minify JavaScripts and Stylesheets withYUI Compressor

    Yahoo!providesan excellentutility for minifying JavaScriptsand stylesheetsso they travelover the wirefaster, theYUI Compressor1. Thanks to Assetic, you can take advantage of this tool very easily.

    The YUI Compressor is no longer maintained by Yahoo2 but by an independent volunteer.Moreover,Yahoohasdecidedto stopall newdevelopmenton YUI3 and to move to other modernalternatives such as Node.js.

    Thats why you arestrongly advised to avoid using YUI utilities unlessstrictly necessary.ReadHow to Minify CSS/JSFiles(UsingUglifyJSandUglifyCSS)for amodernandup-to-datealternative.

    Download the YUI Compressor JARTheYUI Compressoris written in Javaanddistributed asaJAR.DownloadtheJAR4 from the Yahoo!siteand save it toapp/Resources/java/yuicompressor.jar .

    Configure the YUI FiltersNow you needto configuretwo Asseticfilters in your application,one for minifying JavaScriptswith theYUI Compressor and one for minifying stylesheets:

    12

    # app/config/config.ymlassetic :

    1. http://developer.yahoo.com/yui/compressor/

    2. http://www.yuiblog.com/blog/2013/01/24/yui-compressor-has-a-new-owner/

    3. http://yahooeng.tumblr.com/post/96098168666/important-announcement-regarding-yui

    4. https://github.com/yui/yuicompressor/releases

    PDF brought to you bygenerated on March 3, 2015

    Chapter 3: How to Minify JavaScripts and Stylesheets with YUI Compressor | 17

    http://sensiolabs.com
  • Listing 3-2

    Listing 3-3

    Listing 3-4

    345678

    # java: "/usr/bin/java"filters :

    yui_css :jar : "%kernel.root_dir%/Resources/java/yuicompressor.jar"

    yui_js :jar : "%kernel.root_dir%/Resources/java/yuicompressor.jar"

    Windows usersneedto rememberto updateconfig to proper Javalocation. In Windows7 x64 bitby default itsC:\Program Files (x86)\Java\jre6\bin\java.exe .

    You now haveaccessto two new Asseticfilters in your application: yui_css and yui_js . Thesewill usethe YUI Compressor to minify stylesheets and JavaScripts, respectively.

    Minify your AssetsYou haveYUI Compressorconfigurednow, but nothing is going to happenuntil you apply oneof thesefilters to an asset. Since your assets are a part of the view layer, this work is done in your templates:

    123

    {% javascripts @AppBundle/Resources/public/js/* filter =yui_js %}

    {% endjavascripts %}

    Theaboveexampleassumesthat you haveabundlecalledAppBundleandyour JavaScriptfilesarein the Resources/public/ js directory underyour bundle.This isnt important however- you caninclude your JavaScript files no matter where they are.

    With the addition of the yui_js filter to the assettagsabove,you should now seeminified JavaScriptscoming over the wire much faster. The same process can be repeated to minify your stylesheets.

    123

    {% stylesheets @AppBundle/Resources/public/css/* filter =yui_css %}

    {% endstylesheets %}

    Disable Minification in Debug ModeMinified JavaScriptsandStylesheetsareverydifficult to read,let alonedebug.Becauseof this, Asseticletsyou disableacertainfilter whenyour application is in debugmode.You cando this by prefixing the filtername in your templatewith a questionmark: ?. This tells Asseticto only apply this filter when debugmode is off.

    123

    {% javascripts @AppBundle/Resources/public/js/* filter =?yui_js %}

    {% endjavascripts %}

    PDF brought to you bygenerated on March 3, 2015

    Chapter 3: How to Minify JavaScripts and Stylesheets with YUI Compressor | 18

    http://sensiolabs.com
  • Insteadof addingthe filter to the assettags,you canalsogloballyenableit by addingthe apply_toattribute to the filter configuration, for examplein the yui_js filter apply_to: "\.js$" . To onlyhave the filter applied in production, add this to the config_prod file rather than the commonconfig file. For details on applying filters by file extension, seeFiltering Based on a File Extension.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 3: How to Minify JavaScripts and Stylesheets with YUI Compressor | 19

    http://sensiolabs.com
  • Listing 4-1

    Listing 4-2

    Chapter 4

    How to Use Assetic for Image Optimizationwith Twig Functions

    Amongst its many filters, Assetichas four filters which can be used for on-the-fly imageoptimization.This allows you to get the benefitsof smallerfile sizeswithout having to usean imageeditor to processeachimage.The resultsarecachedand canbedumped for production so there is no performancehit foryour end users.

    Using JpegoptimJpegoptim1 is a utility for optimizing JPEGfiles. To useit with Assetic,add the following to the Asseticconfig:

    12345

    # app/config/config.ymlassetic :

    filters :jpegoptim :

    bin : path/to/jpegoptim

    Notice that to usejpegoptim, you must haveit alreadyinstalledon your system.The bin optionpoints to the location of the compiled binary.

    It can now be used from a template:

    1234

    {% image @AppBundle/Resources/public/images/example.jpgfilter =jpegoptim output =/images/example.jpg %}

    {% endimage%}

    1. http://www.kokkonen.net/tjko/projects.html

    PDF brought to you bygenerated on March 3, 2015

    Chapter 4: How to Use Assetic for Image Optimization with Twig Functions | 20

    http://sensiolabs.com
  • Listing 4-3

    Listing 4-4

    Listing 4-5

    Listing 4-6

    Listing 4-7

    Removing all EXIF Data

    By default, running this filter only removessomeof the meta information stored in the file. Any EXIFdata and comments are not removed, but you can remove these by using thestrip_all option:

    123456

    # app/config/config.ymlassetic :

    filters :jpegoptim :

    bin : path/to/jpegoptimstrip_all : true

    Lowering maximum Quality

    Thequality levelof the JPEGis not affectedby default.You cangain further file sizereductionsby settingthe maxquality settinglower than the current levelof the images.This will of coursebeat the expenseofimage quality:

    123456

    # app/config/config.ymlassetic :

    filters :jpegoptim :

    bin : path/to/jpegoptimmax: 70

    Shorter Syntax: Twig FunctionIf youre using Twig, its possibleto achieveall of this with a shorter syntax by enablingand using aspecial Twig function. Start by adding the following config:

    12345678

    # app/config/config.ymlassetic :

    filters :jpegoptim :

    bin : path/to/jpegoptimtwig :

    functions :jpegoptim : ~

    The Twig template can now be changed to the following:

    1

    You can specify the output directory in the config in the following way:

    12345678

    # app/config/config.ymlassetic :

    filters :jpegoptim :

    bin : path/to/jpegoptimtwig :

    functions :jpegoptim : { output : images/*.jpg }

    PDF brought to you bygenerated on March 3, 2015

    Chapter 4: How to Use Assetic for Image Optimization with Twig Functions | 21

    http://sensiolabs.com
  • Listing 5-1

    Listing 5-2

    Chapter 5

    How to Apply an Assetic Filter to a specific FileExtension

    Asseticfilters canbe applied to individual files, groupsof files or even,asyoull seehere,files that havea specificextension.To show you how to handle eachoption, supposethat you want to useAsseticsCoffeeScript filter, which compiles CoffeeScript files into JavaScript.

    The main configuration is just the paths to coffee,node and node_modules.An exampleconfigurationmight look like this:

    1234567

    # app/config/config.ymlassetic :

    filters :coffee :

    bin : /usr/bin/coffeenode: /usr/bin/nodenode_paths: [ /usr/lib/node_modules/ ]

    Filter a single FileYou can now serve up a single CoffeeScript file as JavaScript from within your templates:

    123

    {% javascripts @AppBundle/Resources/public/js/example.coffee filter =coffee %}

    {% endjavascripts %}

    This is all thats needed to compile this CoffeeScript file and serve it as the compiled JavaScript.

    Filter multiple FilesYou can also combine multiple CoffeeScript files into a single output file:

    PDF brought to you bygenerated on March 3, 2015

    Chapter 5: How to Apply an Assetic Filter to a specific File Extension | 22

    http://sensiolabs.com
  • Listing 5-3

    Listing 5-4

    Listing 5-5

    12345

    {% javascripts @AppBundle/Resources/public/js/example.coffee@AppBundle/Resources/public/js/another.coffee

    filter =coffee %}

    {% endjavascripts %}

    Both the files will now be served up as a single file compiled into regular JavaScript.

    Filtering Based on a File ExtensionOneof thegreatadvantagesof usingAsseticis reducingthenumberof assetfiles to lower HTTP requests.In order to make full useof this, it would be good to combineall your JavaScriptand CoffeeScriptfilestogethersincethey will ultimately all be servedasJavaScript.Unfortunately just adding the JavaScriptfiles to the files to becombinedasabovewill not work asthe regularJavaScriptfiles will not survivetheCoffeeScript compilation.

    This problem can be avoidedby using the apply_to option in the config, which allows you to specifywhich filter should alwaysbe applied to particular file extensions.In this caseyou can specifythat thecoffee filter is applied to all.coffee files:

    # app/config/config.ymlassetic:

    filters:coffee:

    bin: /usr/bin/coffeenode: /usr/bin/nodenode_paths: [/usr/lib/node_modules/]apply_to: "\.coffee$"

    With this, you no longer need to specify the coffee filter in the template. You can also list regularJavaScriptfiles, all of which will be combined and renderedas a single JavaScriptfile (with only the.coffee files being run through the CoffeeScript filter):

    12345

    {% javascripts @AppBundle/Resources/public/js/example.coffee@AppBundle/Resources/public/js/another.coffee@AppBundle/Resources/public/js/regular.js %}

    {% endjavascripts %}

    PDF brought to you bygenerated on March 3, 2015

    Chapter 5: How to Apply an Assetic Filter to a specific File Extension | 23

    http://sensiolabs.com
  • Listing 6-1

    Chapter 6

    How to Install 3rd Party Bundles

    Most bundlesprovide their own installation instructions.However,the basicstepsfor installing abundleare the same:

    A) Add Composer Dependencies B) Enable the Bundle C) Configure the Bundle

    A) Add Composer DependenciesDependenciesare managedwith Composer,so if Composeris new to you, learn somebasicsin theirdocumentation1. This has 2 steps:

    1) Find out the Name of the Bundle on Packagist

    The README for a bundle (e.g.FOSUserBundle2) usually tells you its name(e.g. friendsofsymfony/user-bundle ). If it doesnt, you can search for the library on thePackagist.org3 site.

    Looking for bundles?Try searchingat KnpBundles.com4: the unofficial archive of SymfonyBundles.

    2) Install the Bundle via Composer

    Now that you know the package name, you can install it via Composer:

    1 $ composer require friendsofsymfony/user-bundle

    1. http://getcomposer.org/doc/00-intro.md

    2. https://github.com/FriendsOfSymfony/FOSUserBundle

    3. https://packagist.org

    4. http://knpbundles.com/

    PDF brought to you bygenerated on March 3, 2015

    Chapter 6: How to Install 3rd Party Bundles | 24

    http://sensiolabs.com
  • Listing 6-2

    Listing 6-3

    Listing 6-4

    Listing 6-5

    This will choosethe bestversionfor your project,add it to composer.json anddownload the library intothe vendor/ directory. If you needa specificversion,add a : and the versionright after the library name(seecomposer require5).

    B) Enable the BundleAt this point, the bundle is installed in your Symfonyproject (in vendor/ friendsofsymfony/ ) and theautoloaderrecognizesits classes.The only thing you needto do now is registerthe bundle in AppKernel:

    123456789

    1011121314151617

    // app/AppKernel.php

    // ...class AppKernel extends Kernel{

    // ...

    public function registerBundles (){

    $bundles = array (// ...,new FOS\UserBundle\FOSUserBundle(),

    );

    // ...}

    }

    C) Configure the BundleIts pretty common for a bundle to need some additional setup or configuration in app/config/config.yml . The bundlesdocumentationwill tell you about the configuration, but you can alsoget areference of the bundles config via theconfig:dump-reference command.

    For instance, in order to look the reference of theassetic config you can use this:

    1 $ app/console config:dump-reference AsseticBundle

    or this:

    1 $ app/console config:dump-reference assetic

    The output will look like this:

    12345678

    assetic:debug: %kernel.debug%use_controller:

    enabled: %kernel.debug%profiler: false

    read_from: %kernel.root_dir%/../webwrite_to: %assetic.read_from%java: /usr/bin/java

    5. https://getcomposer.org/doc/03-cli.md#require

    PDF brought to you bygenerated on March 3, 2015

    Chapter 6: How to Install 3rd Party Bundles | 25

    http://sensiolabs.com
  • 91011

    node: /usr/local/bin/nodenode_paths: []# ...

    Other SetupAt this point, check theREADMEfile of your brand new bundle to see what to do next. Have fun!

    PDF brought to you bygenerated on March 3, 2015

    Chapter 6: How to Install 3rd Party Bundles | 26

    http://sensiolabs.com
  • Chapter 7

    Best Practices for Reusable Bundles

    There are 2 types of bundles:

    Application-specific bundles: only used to build your application; Reusable bundles: meant to be shared across many projects.

    This article is all about how to structure your reusable bundles so that theyreeasyto configureandextend.Many of theserecommendationsdo not apply to applicationbundlesbecauseyoull want to keepthoseassimpleaspossible.For applicationbundles,just follow thepracticesshownthroughout thebookand cookbook.

    The best practices for application-specific bundles are discussed inThe Symfony Framework Best Practices.

    Bundle NameA bundle is alsoa PHPnamespace.The namespacemust follow the technicalinteroperability standards1

    for PHPnamespacesandclassnames:it startswith a vendorsegment,followed by zeroor morecategorysegments, and it ends with the namespace short name, which must end with aBundlesuffix.

    A namespacebecomesa bundle assoon asyou add a bundle classto it. The bundle classnamemustfollow these simple rules:

    Use only alphanumeric characters and underscores; Use a CamelCased name; Use a descriptive and short name (no more than 2 words); Prefix the name with the concatenation of the vendor (and optionally the category

    namespaces); Suffix the name withBundle.

    Here are some valid bundle namespaces and class names:

    1. http://www.php-fig.org/psr/psr-0/

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 27

    http://sensiolabs.com
  • Listing 7-1

    Namespace Bundle Class Name

    Acme\Bundle\BlogBundle AcmeBlogBundle

    Acme\Bundle\Social\BlogBundle AcmeSocialBlogBundle

    Acme\BlogBundle AcmeBlogBundle

    By convention, thegetName()method of the bundle class should return the class name.

    If you share your bundle publicly, you must use the bundle classname as the name of therepository (AcmeBlogBundleand notBlogBundle for instance).

    SymfonycoreBundlesdo not prefix the Bundleclasswith Symfonyand alwaysadd a Bundle sub-namespace; for example:FrameworkBundle2.

    Eachbundle hasan alias,which is the lower-casedshort versionof the bundle nameusingunderscores(acme_hello for AcmeHelloBundle, or acme_social_blog for Acme\Social\BlogBundle for instance).This alias is used to enforce uniqueness within a bundle (see below for some usage examples).

    Directory StructureThe basic directory structure of a HelloBundle must read as follows:

    123456789

    1011121314

    XXX/...HelloBundle/

    HelloBundle.phpController/Resources/

    meta/LICENSE

    config/doc/

    index.rsttranslations/views/public/

    Tests/

    The XXXdirectory(ies) reflects the namespace structure of the bundle.

    The following files are mandatory:

    HelloBundle.php ; Resources/meta/LICENSE: The full license for the code; Resources/doc/index.rst : The root file for the Bundle documentation.

    These conventions ensure that automated tools can rely on this default structure to work.

    2. http://api.symfony.com/2.6/Symfony/Bundle/FrameworkBundle/FrameworkBundle.html

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 28

    http://sensiolabs.com
  • The depth of sub-directoriesshould be kept to the minimal for most usedclassesand files (2 levelsat amaximum). More levels can be defined for non-strategic, less-used files.

    The bundle directory is read-only.If you needto write temporary files, store them under the cache/ orlog/ directoryof the hostapplication.Tools cangeneratefiles in the bundledirectorystructure,but onlyif the generated files are going to be part of the repository.

    The following classes and files have specific emplacements:

    Type Directory

    Commands Command/

    Controllers Controller/

    Service Container ExtensionsDependencyInjection/

    Event Listeners EventListener/

    Configuration Resources/config/

    Web Resources Resources/public/

    Translation files Resources/translations/

    Templates Resources/views/

    Unit and Functional Tests Tests/

    When building a reusablebundle, model classesshould be placed in the Modelnamespace.SeeHow to ProvideModelClassesfor severalDoctrineImplementationsfor how to handlethe mappingwith a compiler pass.

    ClassesThe bundle directory structure is usedas the namespacehierarchy.For instance,a HelloControllercontroller is stored in Bundle/HelloBundle/ Controller/ HelloController.php and the fully qualifiedclass name isBundle\HelloBundle\Controller\HelloController .

    All classes and files must follow the Symfony codingstandards.

    Someclassesshould be seenas facadesand should be as short as possible,like Commands,Helpers,Listeners, and Controllers.

    Classes that connect to the event dispatcher should be suffixed withListener .

    Exceptions classes should be stored in anException sub-namespace.

    VendorsA bundle must not embedthird-party PHPlibraries. It should rely on the standardSymfonyautoloadinginstead.

    A bundle should not embed third-party libraries written in JavaScript, CSS, or any other language.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 29

    http://sensiolabs.com
  • Listing 7-2

    TestsA bundle should comewith a test suite written with PHPUnit and storedunder the Tests/ directory.Tests should follow the following principles:

    The test suite must be executablewith a simple phpunit command run from a sampleapplication;

    The functional tests should only be used to test the responseoutput and some profilinginformation if you have some;

    The tests should cover at least 95% of the code base.

    A test suite must not contain AllTests.php scripts, but must rely on the existenceof aphpunit.xml.dist file.

    DocumentationAll classes and functions must come with full PHPDoc.

    Extensivedocumentationshouldalsobeprovided in the reStructuredTextformat, under the Resources/doc/ directory; theResources/doc/ index.rst file is theonly mandatoryfile andmustbe theentrypointfor the documentation.

    Installation Instructions

    In order to easethe installation of third-party bundles, consider using the following standardizedinstructions in yourREADME.mdfile.

    123456789

    1011121314151617181920212223242526

    Installation============

    Step 1: Download the Bundle---------------------------

    Open a command console, enter your project directory and execute thefollowing command to download the latest stable version of this bundle:

    bash$ composer require "~1"

    This command requires you to have Composer installed globally, as explainedin the [installation chapter](https://getcomposer.org/doc/00-intro.md)of the Composer documentation.

    Step 2: Enable the Bundle-------------------------

    Then, enable the bundle by adding the following line in the app/AppKernel.phpfile of your project:

    php

  • 272829303132333435363738394041424344

    // ...class AppKernel extends Kernel{

    public function registerBundles(){

    $bundles = array(// ...

    new \\(),);

    // ...}

    // ...}

    This templateassumesthat your bundle is in its 1.x version.If not, changethe "~1" installation versionaccordingly ("~2" , "~3" , etc.)

    Optionally, you canaddmore installation steps(Step3, Step4, etc.) to explainother requiredinstallationtasks, such as registering routes or dumping assets.

    RoutingIf the bundle providesroutes, they must be prefixed with the bundle alias.For an AcmeBlogBundleforinstance, all routes must be prefixed withacme_blog_.

    TemplatesIf a bundle providestemplates,they must useTwig. A bundle must not provide a main layout, exceptifit provides a full working application.

    Translation FilesIf a bundle providesmessagetranslations,they must bedefinedin the XLIFF format; the domain shouldbe named after the bundle name (bundle.hello ).

    A bundle must not override existing messages from another bundle.

    ConfigurationTo provide more flexibility, a bundle can provide configurablesettingsby using the Symfonybuilt-inmechanisms.

    For simple configuration settings,rely on the default parameters entry of the Symfonyconfiguration.Symfonyparametersaresimplekey/valuepairs;avaluebeinganyvalid PHPvalue.Eachparameternameshouldstartwith the bundlealias,though this is just abest-practicesuggestion.The restof the parametername will use a period (. ) to separate different parts (e.g.acme_hello.email.from ).

    The end user can provide values in any configuration file:

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 31

    http://sensiolabs.com
  • Listing 7-3

    Listing 7-4

    Listing 7-5

    123

    # app/config/config.ymlparameters:

    acme_hello.email.from : [email protected]

    Retrieve the configuration parameters in your code from the container:

    1 $container ->getParameter( acme_hello.email.from );

    Even if this mechanismis simple enough,you arehighly encouragedto usethe semanticconfigurationdescribed in the cookbook.

    If you are defining services, they should also be prefixed with the bundle alias.

    Custom Validation ConstraintsStartingwith Symfony2.5, a new Validation API was introduced. In fact, thereare3 modes,which theuser can configure in their project:

    2.4: the original 2.4 and earlier validation API; 2.5: the new 2.5 and later validation API; 2.5-BC: the new 2.5 API with a backwards-compatiblelayer so that the 2.4 API still works.

    This is only available in PHP 5.3.9+.

    As a bundle author, youll want to support both APIs,sincesomeusersmay still be using the 2.4 API.Specifically,if your bundle adds a violation directly to the ExecutionContext 3 (e.g. like in a customvalidation constraint),youll needto checkfor which API is beingused.The following code,would workfor all users:

    123456789

    101112131415161718192021

    use Symfony\Component\Validator\ConstraintValidator ;use Symfony\Component\Validator\Constraint ;use Symfony\Component\Validator\Context\ExecutionContextInterface ;// ...

    class ContainsAlphanumericValidator extends ConstraintValidator{

    public function validate ( $value, Constraint $constraint ){

    if ( $this ->context instanceof ExecutionContextInterface ) {// the 2.5 API$this ->context ->buildViolation ( $constraint ->message)

    ->setParameter( %string% , $value)->addViolation ()

    ;} else {

    // the 2.4 API$this ->context ->addViolation (

    $constraint ->message,array ( %string% => $value)

    );

    3. http://api.symfony.com/2.6/Symfony/Component/Validator/Context/ExecutionContext.html

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 32

    http://sensiolabs.com
  • 222324

    }}

    }

    Learn more from the Cookbook How to Load Service Configuration inside a Bundle

    PDF brought to you bygenerated on March 3, 2015

    Chapter 7: Best Practices for Reusable Bundles | 33

    http://sensiolabs.com
  • Listing 8-1

    Chapter 8

    How to Use Bundle Inheritance to OverrideParts of a Bundle

    When working with third-party bundles, youll probably come acrossa situation where you want tooverridea file in that third-party bundlewith a file in oneof your own bundles.Symfonygivesyou a veryconvenientway to override things like controllers, templates,and other files in a bundlesResources/directory.

    For example, supposethat youre installing the FOSUserBundle1, but you want to override its baselayout.html.twig template, as well as one of its controllers. Supposealso that you have your ownAcmeUserBundlewhereyou want the overriddenfiles to live. Startby registeringthe FOSUserBundleasthe "parent" of your bundle:

    123456789

    101112

    // src/Acme/UserBundle/AcmeUserBundle.phpnamespaceAcme\UserBundle;

    use Symfony\Component\HttpKernel\Bundle\Bundle;

    class AcmeUserBundleextends Bundle{

    public function getParent (){

    return FOSUserBundle;}

    }

    By making this simple change,you can now override severalparts of the FOSUserBundlesimply bycreating a file with the same name.

    Despite the method name, there is no parent/child relationship betweenthe bundles, it is just away to extend and override an existing bundle.

    1. https://github.com/friendsofsymfony/fosuserbundle

    PDF brought to you bygenerated on March 3, 2015

    Chapter 8: How to Use Bundle Inheritance to Override Parts of a Bundle | 34

    http://sensiolabs.com
  • Listing 8-2

    Overriding ControllersSupposeyou want to addsomefunctionality to the registerAction of a RegistrationController thatlivesinsideFOSUserBundle.To do so, just createyour own RegistrationController.php file, overridethe bundles original method, and change its functionality:

    123456789

    101112131415

    // src/Acme/UserBundle/Controller/RegistrationController.phpnamespaceAcme\UserBundle\Controller ;

    use FOS\UserBundle\Controller\RegistrationController as BaseController ;

    class RegistrationController extends BaseController{

    public function registerAction (){

    $response = parent :: registerAction ();

    // ... do custom stuffreturn $response;

    }}

    Depending on how severely you need to change the behavior, you might callparent::registerAction() or completely replace its logic with your own.

    Overriding controllers in this way only works if the bundle refers to the controller using thestandard FOSUserBundle:Registration:register syntax in routes and templates.This is thebest practice.

    Overriding Resources: Templates, Routing, etcMost resourcescan also be overridden, simply by creatinga file in the samelocation as your parentbundle.

    For example,its verycommon to needto overridethe FOSUserBundleslayout.html.twig templatesothat it usesyour applicationsbaselayout. Sincethe file livesat Resources/views/ layout.html.twig inthe FOSUserBundle,you cancreateyour own file in the samelocation of AcmeUserBundle.Symfonywillignore the file that lives inside the FOSUserBundle entirely, and use your file instead.

    The same goes for routing files and some other resources.

    The overriding of resourcesonly works when you refer to resourceswith the @FOSUserBundle/Resources/config/ routing/ security.xml method. If you refer to resourceswithout using the@BundleName shortcut, they cant be overridden in this way.

    Translation and validation files do not work in the same way as described above. Read"Translations" if you want to learnhow to overridetranslationsand see"ValidationMetadata" fortricks to override the validation.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 8: How to Use Bundle Inheritance to Override Parts of a Bundle | 35

    http://sensiolabs.com
  • Chapter 9

    How to Override any Part of a Bundle

    This document is a quick reference for how to override different parts of third-party bundles.

    TemplatesFor information on overriding templates, see

    Overriding Bundle Templates. How to Use Bundle Inheritance to Override Parts of a Bundle

    RoutingRouting is never automatically imported in Symfony. If you want to include the routes from anybundle, then they must be manually imported from somewherein your application (e.g.app/config/routing.yml ).

    The easiestway to "override" a bundles routing is to never import it at all. Instead of importing athird-party bundlesrouting, simply copy that routing file into your application,modify it, and import itinstead.

    ControllersAssumingthe third-party bundle involvedusesnon-servicecontrollers(which is almostalwaysthe case),you caneasilyoverridecontrollersvia bundle inheritance.For more information, seeHow to UseBundleInheritanceto OverridePartsof a Bundle. If the controller is a service,seethe next sectionon how tooverride it.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 9: How to Override any Part of a Bundle | 36

    http://sensiolabs.com
  • Listing 9-1

    Listing 9-2

    Services & ConfigurationIn order to override/extenda service,therearetwo options. First, you cansetthe parameterholding theservicesclassname to your own classby setting it in app/config/ config.yml . This of courseis onlypossibleif the classname is defined as a parameterin the serviceconfig of the bundle containing theservice.For example,to overridetheclassusedfor Symfonystranslator service,you would overridethetranslator.class parameter.Knowing exactlywhich parameterto overridemay take someresearch.For the translator, the parameteris definedandusedin the Resources/config/ translation.xml file inthe core FrameworkBundle:

    123

    # app/config/config.ymlparameters:

    translator.class : Acme\HelloBundle\Translation\Translator

    Secondly,if the classis not availableasaparameter,you want to makesurethe classis alwaysoverriddenwhenyour bundle is usedor if you needto modify somethingbeyondjust the classname,you shouldusea compiler pass:

    123456789

    1011121314

    // src/Acme/DemoBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.phpnamespaceAcme\DemoBundle\DependencyInjection\Compiler;

    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface ;use Symfony\Component\DependencyInjection\ContainerBuilder ;

    class OverrideServiceCompilerPass implements CompilerPassInterface{

    public function process( ContainerBuilder $container ){

    $definition = $container ->getDefinition ( original-service-id );$definition ->setClass ( Acme\DemoBundle\YourService);

    }}

    In this exampleyou fetch the servicedefinition of the original service,and setits classnameto your ownclass.

    SeeHow to Work with CompilerPassesin Bundlesfor information on how to usecompiler passes.If youwant to do somethingbeyondjust overriding the class- like addinga methodcall - you canonly usethecompiler pass method.

    Entities & Entity MappingDue to the way Doctrine works, it is not possibleto override entity mapping of a bundle. However,if a bundle provides a mapped superclass(such as the User entity in the FOSUserBundle)one canoverride attributes and associations.Learn more about this featureand its limitations in the Doctrinedocumentation1.

    FormsIn order to overridea form type, it hasto be registeredasa service(meaningit is taggedasform.type ).You can then override it asyou would override any serviceasexplained in Services& Configuration.This, of course, will only work if the type is referred to by its alias rather than being instantiated, e.g.:

    1. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#overrides

    PDF brought to you bygenerated on March 3, 2015

    Chapter 9: How to Override any Part of a Bundle | 37

    http://sensiolabs.com
  • Listing 9-3

    Listing 9-4

    Listing 9-5

    1 $builder ->add( name, custom_type );

    rather than:

    1 $builder ->add( name, new CustomType());

    Validation MetadataSymfonyloadsall validationconfigurationfiles from everybundleandcombinesthem into onevalidationmetadatatree. This meansyou areable to add new constraintsto a property, but you cannot overridethem.

    To override this, the 3rd party bundle needsto haveconfiguration for validation groups. For instance,the FOSUserBundlehasthis configuration. To createyour own validation, add the constraintsto a newvalidation group:

    123456789

    10

    # src/Acme/UserBundle/Resources/config/validation.ymlFOS\UserBundle\Model\User:

    properties :plainPassword:

    - NotBlank:groups: [ AcmeValidation]

    - Length:min: 6minMessage: fos_user.password.shortgroups: [ AcmeValidation]

    Now, updatethe FOSUserBundleconfiguration,so it usesyour validation groupsinsteadof the originalones.

    TranslationsTranslations are not related to bundles, but to domains. That means that you can override thetranslations from any translation file, as long as it is inthe correct domain.

    The last translation file alwayswins. That meansthat you need to make sure that the bundlecontainingyour translationsis loadedafter any bundle whosetranslationsyoureoverriding. Thisis done inAppKernel.

    The file that alwayswins is the one that is placedin app/Resources/translations , asthosefilesare always loaded last.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 9: How to Override any Part of a Bundle | 38

    http://sensiolabs.com
  • Listing 10-1

    Chapter 10

    How to Remove the AcmeDemoBundle

    The Symfony Standard Edition comes with a complete demo that lives inside a bundle calledAcmeDemoBundle.It is agreatboilerplateto referto while startingaproject,but youll probablywant toeventually remove it.

    This article usesthe AcmeDemoBundleasan example,but you canusethesestepsto removeanybundle.

    1. Unregister the Bundle in theAppKernelTo disconnect the bundle from the framework, you should remove the bundle from theAppKernel::registerBundles() method. The bundle is normally found in the $bundles arraybut theAcmeDemoBundleis only registeredin the developmentenvironmentand you can find it inside the ifstatement below:

    123456789

    10111213141516

    // app/AppKernel.php

    // ...class AppKernel extends Kernel{

    public function registerBundles (){

    $bundles = array ( ... );

    if ( in_array ( $this ->getEnvironment(), array ( dev , test ))) {// comment or remove this line:// $bundles[] = new Acme\DemoBundle\AcmeDemoBundle();// ...

    }}

    }

    PDF brought to you bygenerated on March 3, 2015

    Chapter 10: How to Remove the AcmeDemoBundle | 39

    http://sensiolabs.com
  • Listing 10-2

    2. Remove Bundle ConfigurationNow that Symfonydoesntknow about the bundle, you needto removeany configuration and routingconfiguration inside theapp/config directory that refers to the bundle.

    2.1 Remove Bundle Routing

    The routing for the AcmeDemoBundlecan be found in app/config/ routing_dev.yml . Removethe_acme_demoentry at the bottom of this file.

    2.2 Remove Bundle Configuration

    Somebundles contain configuration in one of the app/config/ config*.yml files. Be sure to removethe relatedconfiguration from thesefiles. You can quickly spot bundle configuration by looking for aacme_demo(or whateverthe nameof the bundle is, e.g. fos_user for the FOSUserBundle)string in theconfiguration files.

    The AcmeDemoBundledoesnthaveconfiguration.However,the bundle is usedin the configuration forthe app/config/ security.yml file. You can use it asa boilerplate for your own security,but you canalso remove everything: it doesnt matter to Symfony if you remove it or not.

    3. Remove the Bundle from the FilesystemNow you haveremovedeveryreferenceto the bundle in your application,you should removethe bundlefrom the filesystem.The bundle is located in the src/ Acme/DemoBundledirectory. You should removethis directory and you can remove theAcmedirectory as well.

    If you dont know the location of a bundle, you canusethe getPath() 1 method to get the path ofthe bundle:

    1 echo $this ->container ->get ( kernel ) ->getBundle( AcmeDemoBundle) ->getPath();

    3.1 Remove Bundle Assets

    Remove the assets of the bundle in the web/ directory (e.g. web/bundles/ acmedemofor theAcmeDemoBundle).

    4. Remove Integration in other Bundles

    This doesntapply to the AcmeDemoBundle- no other bundlesdependon it, soyou canskip thisstep.

    Somebundlesrely on other bundles,if you removeoneof the two, the other will probably not work. Besure that no other bundles, third party or self-made, rely on the bundle you are about to remove.

    1. http://api.symfony.com/2.6/Symfony/Component/HttpKernel/Bundle/BundleInterface.html#getPath()

    PDF brought to you bygenerated on March 3, 2015

    Chapter 10: How to Remove the AcmeDemoBundle | 40

    http://sensiolabs.com
  • If one bundle relies on another, in most casesit means that it usessome servicesfrom thebundle. Searchingfor the bundle aliasstring mayhelp you spot them (e.g.acme_demofor bundlesdepending on AcmeDemoBundle).

    If a third party bundle relies on another bundle, you can find that bundle mentioned in thecomposer.json file included in the bundle directory.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 10: How to Remove the AcmeDemoBundle | 41

    http://sensiolabs.com
  • Listing 11-1

    Chapter 11

    How to Load Service Configuration inside aBundle

    In Symfony,youll find yourselfusing many services.Theseservicescan be registeredin the app/configdirectory of your application. But when you want to decouplethe bundle for usein other projects,youwant to include the service configuration in the bundle itself. This article will teach you how to do that.

    Creating an Extension ClassIn order to load serviceconfiguration, you have to createa DependencyInjection Extension for yourbundle. This classhassomeconventionsin order to be detectedautomatically.But youll later seehowyou canchangeit to your own preferences.By default, the Extensionhasto comply with the followingconventions:

    It has to live in theDependencyInjection namespace of the bundle; The name is equal to the bundle namewith the Bundle suffix replacedby Extension (e.g.

    the Extension class of the AppBundle would be called AppExtension and the one forAcmeHelloBundle would be calledAcmeHelloExtension).

    The Extensionclassshould implement the ExtensionInterface 1, but usuallyyou would simply extendthe Extension 2 class:

    12345678

    // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.phpnamespaceAcme\HelloBundle\DependencyInjection ;

    use Symfony\Component\HttpKernel\DependencyInjection\Extension ;use Symfony\Component\DependencyInjection\ContainerBuilder ;

    class AcmeHelloExtension extends Extension{

    1. http://api.symfony.com/2.6/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.html

    2. http://api.symfony.com/2.6/Symfony/Component/DependencyInjection/Extension/Extension.html

    PDF brought to you bygenerated on March 3, 2015

    Chapter 11: How to Load Service Configuration inside a Bundle | 42

    http://sensiolabs.com
  • Listing 11-2

    Listing 11-3

    910111213

    public function load ( array $configs , ContainerBuilder $container ){

    // ... youll load the files here later}

    }

    Manually Registering an Extension Class

    When not following the conventions,you will have to manually registeryour extension.To do this,you should override the Bundle::getContainerExtension() 3 method to return the instanceof theextension:

    123456789

    10

    // ...use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass ;

    class AcmeHelloBundleextends Bundle{

    public function getContainerExtension (){

    return new UnconventionalExtensionClass ();}

    }

    Sincethe new Extensionclassnamedoesntfollow the naming conventions,you should also overrideExtension::getAlias() 4 to return the correct DI alias.The DI alias is the nameused to refer to thebundle in the container (e.g. in the app/config/ config.yml file). By default, this is done by removingthe Extension suffix and convertingthe classnameto underscores(e.g.AcmeHelloExtensionsDI aliasis acme_hello).

    Using theload() MethodIn the load() method, all servicesand parametersrelatedto this extensionwill be loaded.This methoddoesntget the actual container instance,but a copy. This containeronly has the parametersfrom theactual container. After loading the servicesand parameters,the copy will be merged into the actualcontainer, to ensure all services and parameters are also added to the actual container.

    In the load() method,you canusePHPcodeto registerservicedefinitions, but it is morecommon if youput thesedefinitions in a configuration file (using the Yaml, XML or PHP format). Luckily, you canusethe file loaders in the extension!

    For instance,assumeyou havea file called services.xml in the Resources/config directory of yourbundle, your load method looks like:

    12345678

    use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;use Symfony\Component\Config\FileLocator ;

    // ...public function load ( array $configs , ContainerBuilder $container ){

    $loader = new XmlFileLoader($container ,

    3. http://api.symfony.com/2.6/Symfony/Component/HttpKernel/Bundle/Bundle.html#build()

    4. http://api.symfony.com/2.6/Symfony/Component/DependencyInjection/Extension/Extension.html#getAlias()

    PDF brought to you bygenerated on March 3, 2015

    Chapter 11: How to Load Service Configuration inside a Bundle | 43

    http://sensiolabs.com
  • 9101112

    new FileLocator ( __DIR__. /../Resources/config ));$loader -> load ( services.xml );

    }

    Other available loaders are theYamlFileLoader, PhpFileLoader and IniFileLoader .

    The IniFileLoader can only be used to load parameters and it can only load them as strings.

    Using Configuration to Change the Services

    The Extension is also the class that handles the configuration for that particular bundle (e.g. theconfiguration in app/config/ config.yml ). To read more about it, seethe "How to CreateFriendlyConfiguration for a Bundle" article.

    PDF brought to you bygenerated on March 3, 2015

    Chapter 11: How to Load Service Configuration inside a Bundle | 44

    http://sensiolabs.com
  • Listing 12-1

    Chapter 12

    How to Create Friendly Configuration for aBundle

    If you openyour applicationconfiguration file (usuallyapp/config/ config.yml ), youll seea numberofdifferent configuration "namespaces",suchasframework, twig and doctrine . Eachof theseconfiguresa specificbundle, allowing you to configure things at a high leveland then let the bundle makeall thelow-level, complex changes based on your settings.

    For example,the following tells the FrameworkBundleto enablethe form integration,which involvesthedefinition of quite a few services as well as integration of other related components:

    12

    framework:form: true

    Using Parameters to Configure your Bundle

    If you dont haveplans to shareyour bundle betweenprojects, it doesntmakesenseto use thismore advancedway of configuration. Sinceyou usethe bundle only in one project, you can justchange the service configuration each time.

    If you dowant to beableto configuresomethingfrom within config.yml , you canalwayscreateaparameter there and use that parameter somewhere else.

    Using the Bundle ExtensionThe basic idea is that instead of having the user override individual parameters,you let the userconfigure just a few, specificallycreated,options. As the bundle developer,you then parsethrough thatconfiguration and load correct services and parameters inside an "Extension" class.

    As an example,imagineyou arecreatinga socialbundle, which provides integration with Twitter andsuch.To be able to reuseyour bundle, you haveto make the client_id and client_secret variablesconfigurable. Your bundle configuration would look like:

    PDF brought to you bygenerated on March 3, 2015

    Chapter 12: How to Create Friendly Configuration for a Bundle | 45

    http://sensiolabs.com
  • Listing 12-2

    Listing 12-3

    Listing 12-4

    12345

    # app/config/config.ymlacme_social:

    twitter :client_id : 123client_secret : $ecret

    Read more about the extension inHow to Load Service Configuration inside a Bundle.

    If a bundle provides an Extension class, then you should not generally override any servicecontainer parametersfrom that bundle. The idea is that if an Extensionclassis present,everysetting that should be configurableshould be presentin the configuration madeavailableby thatclass.In other words, the extensionclassdefinesall the public configuration settingsfor whichbackward compatibility will be maintained.

    For parameterhandling within a DependencyInjection classseeUsing Parameterswithin a DependencyInjection Class.

    Processing the$configs Array

    First things first, you haveto createan extensionclassasexplainedin How to LoadServiceConfigurationinside a Bundle.

    Whenever a user includes the acme_social key (which is the DI alias) in a configuration file, theconfiguration under it is addedto an arrayof configurationsand passedto the load() method of yourextension (Symfony automatically converts XML and YAML to an array).

    For the configurationexamplein the previoussection,the arraypassedto your load() methodwill looklike this:

    12345678

    array (array (

    twitter => array (client_id => 123,client_secret => $ecret ,

    ),),

    )

    Notice that this is an array of arrays, not just a single flat array of the configuration values.This isintentional, as it allows Symfonyto parseseveralconfiguration resources.For example,if acme_socialappears in another configuration file - say config_dev.yml - with different values beneath it, theincoming array might look like this:

    123456789

    array (// values from config.ymlarray (

    twitter => array (client_id => 123,client_secret => $secret ,

    ),),// values from config_dev.yml

    PDF brought to you bygenerated on March 3, 2015

    Chapter 12: How to Create Friendly Configuration for a Bundle | 46

    http://sensiolabs.com
  • Listing 12-5

    Listing 12-6

    101112131415

    array (twitter => array (

    client_id => 456,),

    ),)

    The order of the two arrays depends on which one is set first.

    But dont worry! SymfonysConfig componentwill help you mergethesevalues,provide defaultsandgive the user validation errors on bad configuration. Hereshow it works. Create a Configurationclassin the DependencyInjection directory and build a tree that definesthe structureof your bundlesconfiguration.

    The Configuration class to handle the sample configuration looks like:

    123456789

    101112131415161718192021222324252627

    // src/Acme/SocialBundle/DependencyInjection/Configuration.phpnamespaceAcme\SocialBundle\DependencyInjection ;

    use Symfony\Component\Config\Definition\Builder\TreeBuilder ;use Symfony\Component\Config\Definition\ConfigurationInterface ;

    class Configuration implements ConfigurationInterface{

    public function getConfigTreeBuilder (){

    $treeBuilder = new TreeBuilder ();$rootNode = $treeBuilder ->root ( acme_social );

    $rootNode->children ()

    ->arrayNode( twitter )->children ()

    -> integerNode( client_id ) ->end()->scalarNode( client_secret ) ->end()

    ->end()->end() // twitter

    ->end();

    return $treeBuilder ;}

    }

    The Configuration classcan be muchmore complicatedthan shownhere,supporting"prototype" nodes,advancedvalidation,XML-specificnormalizationandadvancedmerging.Youcanreadmoreaboutthis in theConfigcomponentdocumentation. Youcanalsoseeit in actionbycheckingout someof thecoreConfigurationclasses, such as the one from theFrameworkBundle Configuration1 or theTwigBundle Configuration2.

    This classcannow be usedin your load() method to mergeconfigurationsand forcevalidation (e.g. ifan additional option was passed, an exception will be thrown):

    12

    public function load ( array $configs , ContainerBuilder $container ){

    1. https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php2. https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php

    PDF brought to you bygenerated on March 3, 2015

    Chapter 12: How to Create Friendly Configuration for a Bundle | 47

    http://sensiolabs.com
  • Listing 12-7

    Listing 12-8

    34567

    $configuration = new Configuration ();

    $config = $this ->processConfiguration ( $configuration , $configs );// ...

    }

    The processConfiguration() methodusesthe configuration treeyouvedefinedin the Configurationclass to validate, normalize and merge all of the configuration arrays together.

    Instead of calling processConfiguration() in your extension each time you provide someconfiguration options, you might want to use the ConfigurableExtension 3 to do thisautomatically for you:

    123456789

    1011121314

    // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.phpnamespaceAcme\HelloBundle\DependencyInjection ;

    use Symfony\Component\DependencyInjection\ContainerBuilder ;use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension ;

    class AcmeHelloExtension extends ConfigurableExtension{

    // note that this method is called loadInternal and not loadprotected function loadInternal ( array $mergedConfig, ContainerBuilder $container ){

    // ...}

    }

    This classusesthe getConfiguration() method to get the Configuration instance,you shouldoverrideit if your Configuration classis not calledConfiguration or if it is not placedin the samenamespace as the extension.

    Processing the Configuration yourself

    Using the Config component is fully optional. The load() method getsan arrayof configurationvalues.You can simply parsethesearraysyourself (e.g. by overriding configurationsand usingisset 4 to check for the existence of a value). Be aware that itll be very hard to support XML.

    123456789

    10

    public function load ( array $configs , ContainerBuilder $container ){

    $config = array ();/