Skip to content

andreia/awesome-symfony

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 

Repository files navigation

Awesome Symfony

A curated list of useful Symfony snippets.

Contributions are highly encouraged and very welcome :)

Table of Contents

Configuration

Assets

Assets Base URL

Symfony 2.6

# app/config/config.yml
framework:
    templating:
        assets_base_urls:
            http: ['http://cdn.domain.com']
            ssl:  ['https://secure.domain.com']
        packages:
            # ...

Symfony 2.7+

# app/config/config.yml
framework:
    assets:
        base_path: ~
        base_urls: ['http://cdn.domain.com', 'https://secure.domain.com']

[1]

Assets Base URL (Protocol-Relative)

# app/config/config.yml 
framework: 
    templating: 
        assets_base_urls: '//static.domain.com/images'

Assets Versioning

Symfony 2.6

# app/config/config.yml
framework:
    templating:
        assets_version: 'v5'
        assets_version_format: '%%s?version=%%s'

Symfony 2.7+

# app/config/config.yml
framework:
    assets:
        version: 'v5'
        version_format: '%%s?version=%%s'

[1]

Named Assets

# app/config/config.yml 
assetic:
    assets:
        bootstrap_js:
            inputs:
                - '@AppBundle/Resources/public/js/jquery.js'
                - '@AppBundle/Resources/public/js/bootstrap.js'

Using in Twig templates:

{% javascripts
    '@bootstrap_js'
    '@AppBundle/Resources/public/js/*' %}
        <script src="{{ asset_url }}"></script>
{% endjavascripts %}

Context-Aware CDNs

# app/config/config.yml
framework:
    assets:
        base_urls:
            - 'http://static1.domain.com/images/'
            - 'https://static2.domain.com/images/'

Using in Twig templates:

{{ asset('logo.png') }}
{# in a regular page: http://static1.domain.com/images/logo.png #}
{# in a secure page:  https://static2.domain.com/images/logo.png #}

[1]

Packages (Different Base URLs)

To specify different base URLs for assets, group them into packages:

# app/config/config.yml
framework:
    # ...
    assets:
        packages:
            avatars:
                base_urls: 'http://static_cdn.domain.com/avatars'

Using the avatars package in a Twig template:

<img src="{{ asset('...', 'avatars') }}" />

Directories, Paths

Get the Project Root Directory

Use the config parameter %kernel.root_dir%/../:

some_service:
    class: \path\to\class
    arguments: [%kernel.root_dir%/../]

Symfony 2 In a Controller:

$projectRoot = $this->container->getParameter('kernel.root_dir');

Symfony 3.3

In a Controller:

$projectRoot = $this->get('kernel')->getProjectDir();

Symfony 4+

Using autowiring (argument binding):

# config/services.yaml
services:
    _defaults:
        bind:
            string $projectDir: '%kernel.project_dir%'

Then in your class:

class YourClass
{
    private $projectDir;

    public function __construct(string $projectDir)
    {
        $this->$projectDir = $projectDir;
    }

    // ...

Email Errors

Email Logs Related to 5xx Errors (action_level: critical)

# app/config/config_prod.yml 
monolog:
    handlers:
        mail:
            type: fingers_crossed
            action_level: critical
            handler: buffered
        buffered:
            type: buffer
            handler: swift
        swift:
            type: swift_mailer
            from_email: error@domain.com
            to_email: error@domain.com
            subject: An Error Occurred!
            level: debug

Email Logs Related to 4xx Errors (action_level: error)

# app/config/config_prod.yml
monolog:
    handlers:
        mail:
            type: fingers_crossed
            action_level: error
            handler: buffered
        buffered:
            type: buffer
            handler: swift
        swift:
            type: swift_mailer
            from_email: error@domain.com
            to_email: error@domain.com
            subject: An Error Occurred!
            level: debug

Do Not Email Logs for 404 Errors (excluded_404)

# app/config/config_prod.yml
monolog:
    handlers:
        mail:
            type: fingers_crossed
            action_level: error
            excluded_404:
                - ^/
            handler: buffered 
        buffered:
            type: buffer
            handler: swift
        swift:
            type: swift_mailer
            from_email: error@domain.com
            to_email: error@domain.com
            subject: An Error Occurred!
            level: debug

Import

Import Mixed Configuration Files

# app/config/config.yml
imports:
    - { resource: '../common/config.yml' }
    - { resource: 'dynamic-config.php' }
    - { resource: 'parameters.ini' }
    - { resource: 'security.xml' }
    # ...

Import All Resources From a Directory

# app/config/config.yml
imports:
    - { resource: '../common/' }
    - { resource: 'acme/' }
    # ...

Import Configuration Files Using Glob Patterns

Symfony 3.3

# app/config/config.yml
imports:
    - { resource: "*.yml" }
    - { resource: "common/**/*.xml" }
    - { resource: "/etc/myapp/*.{yml,xml}" }
    - { resource: "bundles/*/{xml,yaml}/services.{yml,xml}" }
    # ...

[1]

Log

Enable the Monolog processor PsrLogMessageProcessor

# app/config/config_prod.yml
services:
    monolog_processor:
        class: Monolog\Processor\PsrLogMessageProcessor
        tags:
            - { name: monolog.processor }

Hide Event Logs

# app/config/dev.yml
monolog:
    handlers:
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
            channels: "!event"

Organizing Log Files Using Channels (Log Messages to Different Files)

# app/config/config_prod.yml
monolog:
    handlers:
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
            channels: ["!event"]
        security:
            type: stream
            path: "%kernel.logs_dir%/security-%kernel.environment%.log"
            level: debug
            channels: "security"

[1]

Security

Impersonating Users

# app/config/security.yml
security:
    firewalls:
        main:
            # ...
            switch_user: true

Switching the user in the URL: http://domain.com/path?_switch_user=john

Session

Define Session Lifetime

# app/config/config.yml
framework:
    session:
        cookie_lifetime: 3600

Profiler

Enable the Profiler on Prod For Specific Users

# app/config/config.yml
framework:
    # ...
    profiler:
       matcher:
           service: app.profiler_matcher

services:
    app.profiler_matcher:
        class: AppBundle\Profiler\Matcher
        arguments: ["@security.context"]
namespace AppBundle\Profiler; 

use Symfony\Component\Security\Core\SecurityContext; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\RequestMatcherInterface; 

class Matcher implements RequestMatcherInterface 
{ 
    protected $securityContext; 

    public function __construct(SecurityContext $securityContext)
    {
        $this->securityContext = $securityContext; 
    } 

    public function matches(Request $request)
    { 
        return $this->securityContext->isGranted('ROLE_ADMIN'); 
    }
}

Console

Parallel Asset Dump

Symfony 2.8

    $ php app/console --env=prod assetic:dump --forks=4

Symfony 3+

    $ php bin/console --env=prod assetic:dump --forks=4

Controller

Cookie

Set a Cookie

use Symfony\Component\HttpFoundation\Cookie;

$response->headers->setCookie(new Cookie('site', 'bar'));

Directories, Paths, and Filesystem

Root Directory of the Project

The parameter kernel.root_dir points to the app directory. To get to the root project directory, use kernel.root_dir/../

realpath($this->getParameter('kernel.root_dir')."/../")

Check If a Path is Absolute

use Symfony\Component\Filesystem\Filesystem;

//...

$fs = new FileSystem();
$fs->isAbsolutePath('/tmp'); // return true
$fs->isAbsolutePath('c:\\Windows'); // return true
$fs->isAbsolutePath('tmp'); // return false
$fs->isAbsolutePath('../dir'); // return false

[1]

Download

Download (Serve) a Static File

use Symfony\Component\HttpFoundation\BinaryFileResponse;

// ...

return new BinaryFileResponse('path/to/file');

Check If a File Exists

use Symfony\Component\Filesystem\Filesystem;

//...

$fs = new FileSystem();
if (!$fs->exists($filepath)) {
    throw $this->createNotFoundException();
}

[1]

Download a File Without Directly Expose it and Change the Filename

use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\Filesystem\Filesystem;

$filename = // define your filename
$basePath = $this->getParameter('kernel.root_dir').'/../uploads';
$filePath = $basePath.'/'.$filename;

$fs = new FileSystem();
if (!$fs->exists($filepath)) {
    throw $this->createNotFoundException();
}

$response = new BinaryFileResponse($filePath);
$response->trustXSendfileTypeHeader();
$response->setContentDisposition(
    ResponseHeaderBag::DISPOSITION_INLINE,
    $filename,
    iconv('UTF-8', 'ASCII//TRANSLIT', $filename)
);

return $response;

Using X-Sendfile Header with BinaryFileResponse

BinaryFileResponse supports X-Sendfile (Nginx and Apache). To use of it, you need to determine whether or not the X-Sendfile-Type header should be trusted and call trustXSendfileTypeHeader() if it should:

BinaryFileResponse::trustXSendfileTypeHeader();

or

$response = new BinaryFileResponse($filePath);
$response->trustXSendfileTypeHeader();

Flash Messages

Set Multiple Flash Messages

use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

$session->getFlashBag()->add(
    'warning',
    'Your config file is writable, it should be set read-only'
);
$session->getFlashBag()->add('error', 'Failed to update name');
$session->getFlashBag()->add('error', 'Invalid email');

[1]

Form

Get Errors for All Form Fields

Symfony 2.5+

$allErrors = $form->getErrors(true);

JSON

Avoiding XSSI JSON Hijacking (only GET requests are vulnerable)

Pass an associative array as the outer-most array to JsonResponse and not an indexed array so that the final result is an object: {"object": "not inside an array"} instead of an array: [{"object": "inside an array"}]

Create a JSON Response with JsonResponse Class

use Symfony\Component\HttpFoundation\JsonResponse;

$response = new JsonResponse();
$response->setData(array(
    'name' => 'John'
));

Create a JSON Response with Response Class

use Symfony\Component\HttpFoundation\Response;

$response = new Response();
$response->setContent(json_encode(array(
    'name' => 'John',
)));
$response->headers->set('Content-Type', 'application/json');

Set JSONP Callback Function

$response->setCallback('handleResponse');

Redirect

Redirect to Another URL

return $this->redirect('http://domain.com');

or

use Symfony\Component\HttpFoundation\RedirectResponse;

$response = new RedirectResponse('http://domain.com');

Request

Get the Request Object

Symfony 2

namespace Acme\FooBundle\Controller;

class DemoController
{
   public function showAction()
   {
       $request = $this->getRequest();
       // ...
   }
}

Symfony 3

namespace Acme\FooBundle\Controller;

use Symfony\Component\HttpFoundation\Request;

class DemoController
{
   public function showAction(Request $request)
   {
       // ...
   }
}

[1]

Get the Request Raw Data Sent with the Request Body

$content = $request->getContent();

Fetch a GET Parameter

$request->query->get('site');

Fetch a GET Parameter in array format (data['name'])

$request->query->get('data')['name'];

Fetch a POST Parameter

$request->request->get('name');

Fetch a GET Parameter Specifying the Data Type

$isActive = $request->query->getBoolean('active');
$page     = $request->query->getInt('page'); 

Other methods are:

  • getAlpha('param');
  • getAlnum('param');
  • getDigits('param'); [1]

Response

Set a HTTP Status Code

use Symfony\Component\HttpFoundation\Response;

$response->setStatusCode(Response::HTTP_NOT_FOUND);

Routing

External URLs

google_search:
    path: /search
    host: www.google.com
<a href="{{ url('google_search', {q: 'Jules Verne'}) }}">Jules Verne</a>

External URLs - Using a Key to Reference a URL

framework:
    assets:
        packages:
            symfony_site:
                version: ~
                base_urls: 'https://symfony.com/images'

Add images from the URL above into your views, using the "symfony_site" key in the second argument of asset():

<img src="{{ asset('logos/header-logo.svg', 'symfony_site') }}">

Generate Absolute URL

Symfony 2

$this->generateUrl('blog_show', array('slug' => 'my-blog-post'), true);

Symfony 3

$this->generateUrl('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL);

Trailing Slash with an Optional Parameter

my_route:
    pattern:  /blog/{var}
    defaults: { _controller: TestBundle:Blog:index, var: ''}
    requirements:
        var: ".*"

Service

Retrieve a Service

$this->get('service.name');

or

$this->container->get('service.name'),

Symfony 4+

Using autowiring, just type-hint the desired service. E.g. getting the routing service:

use Symfony\Component\Routing\RouterInterface;

class SomeClass
{
    private $router;

    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }

    public function doSomething($id)
    {
        $url = $this->router->generate('route_name', ['id' => $id]);

        // ...
    }

    // ...

YAML

Parse YAML File

use Symfony\Component\Yaml\Exception\ParseException;

try {
    $value = Yaml::parse(file_get_contents('/path/to/file.yml'));
} catch (ParseException $e) {
    printf("Unable to parse the YAML string: %s", $e->getMessage());
}

[1]

Environment Variables

Custom Loader for Environment Variables

Symfony 4.4

# config/services.yaml
bind:
    string $name: '%env(name)%'

Implement the EnvVarLoaderInterface in a service:

namespace App\Env;

use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;

class ConsulEnvVarLoader implements EnvVarLoaderInterface
{
    public function loadEnvVars(): array
    {
        $response = file_get_contents('http://127.0.0.1:8500/v1/kv/website-config');

        $consulValue = json_decode($response, true)[0]['Value'];
        $decoded = json_decode(base64_decode($consulValue), true);

        // e.g.:
        // array:1 [
        //     "name" => "my super website"
        // ]

        return $decoded;
    }
}

Update the consul KV:

./consul  kv put website-config '{"name": "Symfony read this var from consul"}'

[1]

Twig

Absolute URLs

Symfony 2.6

{{ asset('logo.png', absolute = true) }}

Symfony 2.7+

{{ absolute_url(asset('logo.png')) }}

Assets Versioning

Symfony 2.6

{{ asset('logo.png', version = 'v5') }}

Symfony 2.7+ Version is automatically appended.

{{ asset('logo.png') }}

{# use the asset_version() function if you need to output it manually #}
{{ asset_version('logo.png') }}

[1]

Get the Authenticated Username

{{ app.user.username }}

Localized Date String

In your Twig template, you can use pre-defined or custom date formats with the localizeddate:

{{ blog.created|localizeddate('none', 'none', 'pt_BR', null, "cccc, d MMMM Y 'às' hh:mm aaa")}}

The pattern "cccc, d MMMM Y 'às' hh:mm aaa" will show the date in this format:

domingo, 5 janeiro 2014 às 03:00 am

Get the Base URL

{{ app.request.getSchemeAndHttpHost() }}

Inject All GET Parameters in a Route

{{ path('home', app.request.query.all) }}

Make the form_rest() and form_end() not Display a Specific Field

Mark the field as rendered (setRendered)

{% do form.somefield.setRendered %}

Render a Template without a Specific Controller for a Static Page

Use the special controller FrameworkBundle:Template:template in the route definition:

# AppBundle/Resources/config/routing.yml
static_page:
    path: /about
    defaults:
        _controller: FrameworkBundle:Template:template
        template: AppBundle:default:about.html.twig

Override the 404 Error Template

Create a new error404.html.twig template at:

app/Resources/TwigBundle/views/Exception/

[1]

Render a Controller Asynchronously

{{ render_hinclude(controller('AppBundle:Features:news', {
    'default': 'Loading...'
})) }}

[1]

Render Just the Close Form HTML Tag

{{ form_end(form, {'render_rest': false}) }}

Using Localized Data (Date, Currency, Number, ...)

Enable the intl twig extension in config.yml or services.yml file:

services:
    twig.extension.intl:
        class: Twig_Extensions_Extension_Intl
        tags:
            - { name: twig.extension }

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •