Skip to content

Commit

Permalink
feature #21819 [Twig Bridge] A simpler way to retrieve flash messages…
Browse files Browse the repository at this point in the history
… (javiereguiluz)

This PR was squashed before being merged into the 3.3-dev branch (closes #21819).

Discussion
----------

[Twig Bridge] A simpler way to retrieve flash messages

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Getting flash messages in templates is more complex than it could be. Main problems:

1. It's too low level: you need to get the "flash bag" (and first, learn what a "flash bag" is) and then you need to call the internal method: `all()`, `get()`, etc.
2. You need to be careful because the session will start automatically when you ask for flashes (even if there are no flashes). You can prevent this with the `{% if app.session is not null and app.session.started %}` code, but it's boring to always use that.

So, I propose to add a new `app.flashes` helper that works as follows.

---

## Get all the flash messages

### Before

```twig
{% if app.session is not null and app.session.started %}
    {% for label, messages in app.session.flashbag.all %}
        {% for message in messages %}
            <div class="alert alert-{{ label }}">
                {{ message }}
            </div>
        {% endfor %}
    {% endfor %}
{% endif %}
```

### After

```twig
{% for label, messages in app.flashes %}
    {% for message in messages %}
        <div class="alert alert-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}
```

---

## Get only the flashes of type `notice`

```twig
{% if app.session is not null and app.session.started %}
    {% for message in app.session.flashbag.get('notice') %}
        <div class="alert alert-notice">
            {{ message }}
        </div>
    {% endfor %}
{% endif %}
```

### After

```twig
{% for message in app.flashes('notice') %}
    <div class="alert alert-notice">
        {{ message }}
    </div>
{% endfor %}
```

---

As an added bonus, you can get any number of flash messages because the method allows to pass an array of flash types:

```twig
{% for label, messages in app.flashes(['warning', 'error']) %}
    {% for message in messages %}
        <div class="alert alert-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}
```

Commits
-------

5a56b23 [Twig Bridge] A simpler way to retrieve flash messages
  • Loading branch information
fabpot committed Mar 23, 2017
2 parents 3de0d9b + 5a56b23 commit db8d87d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/Symfony/Bridge/Twig/AppVariable.php
Expand Up @@ -145,4 +145,35 @@ public function getDebug()

return $this->debug;
}

/**
* Returns some or all the existing flash messages:
* * getFlashes() returns all the flash messages
* * getFlashes('notice') returns a simple array with flash messages of that type
* * getFlashes(array('notice', 'error')) returns a nested array of type => messages.
*
* @return array
*/
public function getFlashes($types = null)
{
// needed to avoid starting the session automatically when looking for flash messages
try {
$session = $this->getSession();
if (null === $session || !$session->isStarted()) {
return array();
}
} catch (\RuntimeException $e) {
return array();
}

if (null === $types || '' === $types || array() === $types) {
return $session->getFlashBag()->all();
}

if (is_string($types)) {
return $session->getFlashBag()->get($types);
}

return array_intersect_key($session->getFlashBag()->all(), array_flip($types));
}
}
78 changes: 78 additions & 0 deletions src/Symfony/Bridge/Twig/Tests/AppVariableTest.php
Expand Up @@ -5,6 +5,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Session;

class AppVariableTest extends TestCase
Expand Down Expand Up @@ -157,6 +158,62 @@ public function testGetSessionWithRequestStackNotSet()
$this->appVariable->getSession();
}

public function testGetFlashesWithNoRequest()
{
$this->setRequestStack(null);

$this->assertEquals(array(), $this->appVariable->getFlashes());
}

public function testGetFlashesWithNoSessionStarted()
{
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('getSession')->willReturn(new Session());

$this->setRequestStack($request);

$this->assertEquals(array(), $this->appVariable->getFlashes());
}

public function testGetFlashes()
{
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(null));

$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(''));

$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(array()));

$flashMessages = $this->setFlashMessages();
$this->assertEquals(array(), $this->appVariable->getFlashes('this-does-not-exist'));

$flashMessages = $this->setFlashMessages();
$this->assertEquals(array(), $this->appVariable->getFlashes(array('this-does-not-exist')));

$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages['notice'], $this->appVariable->getFlashes('notice'));

$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice']),
$this->appVariable->getFlashes(array('notice'))
);

$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice']),
$this->appVariable->getFlashes(array('notice', 'this-does-not-exist'))
);

$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice'], 'error' => $flashMessages['error']),
$this->appVariable->getFlashes(array('notice', 'error'))
);
}

protected function setRequestStack($request)
{
$requestStackMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
Expand All @@ -175,4 +232,25 @@ protected function setTokenStorage($user)

$token->method('getUser')->willReturn($user);
}

private function setFlashMessages()
{
$flashMessages = array(
'notice' => array('Notice #1 message'),
'warning' => array('Warning #1 message'),
'error' => array('Error #1 message', 'Error #2 message'),
);
$flashBag = new FlashBag();
$flashBag->initialize($flashMessages);

$session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')->getMock();
$session->method('isStarted')->willReturn(true);
$session->method('getFlashBag')->willReturn($flashBag);

$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('getSession')->willReturn($session);
$this->setRequestStack($request);

return $flashMessages;
}
}

0 comments on commit db8d87d

Please sign in to comment.