<p dir="auto"><strong>Symfony version(s) affected</strong>: Probably all of them, but I am currently in 4.1</p>
<p dir="auto"><strong>Description</strong></p>
<p dir="auto">When you try to put the Translator Path in an envrionment variable, Symfony try to check if the Path exist <strong>BEFORE</strong> the compilation of the envrionment variable.</p>
<p dir="auto">So with <code class="notranslate">'%env(resolve:PATH_TRANSLATION)%'</code>, Symfony throw an UnexpectedValueException : <code class="notranslate">%env(resolve:PATH_TRANSLATION)% defined in translator.paths does not exist or is not a directory</code>.</p>
<p dir="auto">A second Exception is thrown after that, EnvParameterException : <code class="notranslate">Incompatible use of dynamic environment variable "resolve:PATH_TRANSLATION" found in parameters.</code></p>
<p dir="auto"><strong>How to reproduce</strong></p>
<p dir="auto">You can reproduce the bug easily by adding an environment variable (in <code class="notranslate">.env</code>) and resolve it in the config file.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="framework:
    translator:
        paths:
            - '%env(resolve:PATH_TRANSLATION)%'"><pre class="notranslate"><code class="notranslate">framework:
    translator:
        paths:
            - '%env(resolve:PATH_TRANSLATION)%'
</code></pre></div>
<p dir="auto"><strong>Possible Solution</strong></p>
<p dir="auto">Symfony should resolve the environment variable before checking if the file exist or not.</p>
<p dir="auto"><strong>Additional context</strong></p>
<p dir="auto">Symfony bump into here ==&gt; <a href="https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L1020">https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L1020</a></p>
<h2 dir="auto">The problem</h2>
<p dir="auto">As many of you know, the <code class="notranslate">getRoles()</code> method of the <code class="notranslate">UserInterface</code> doesn't take into account the role hierarchy that you may have defined in your application.</p>
<p dir="auto">That's why usually you must end up with a code similar to the following:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\User\UserInterface;

private $roleHierarchy;

public function __construct(RoleHierarchyInterface $roleHierarchy = null)
{
    $this-&gt;roleHierarchy = $roleHierarchy;
}

private function userHasRole(UserInterface $user, $roleName)
{
    if (null === $this-&gt;roleHierarchy) {
        return in_array($roleName, $user-&gt;getRoles(), true);
    }

    foreach ($this-&gt;roleHierarchy-&gt;getReachableRoles($user-&gt;getRoles()) as $role) {
        if ($roleName === $role-&gt;getRole()) {
            return true;
        }
    }

    return false;
}"><pre class="notranslate"><span class="pl-k">use</span> <span class="pl-v">Symfony</span>\<span class="pl-v">Component</span>\<span class="pl-v">Security</span>\<span class="pl-v">Core</span>\<span class="pl-v">Role</span>\<span class="pl-v">RoleHierarchyInterface</span>;
<span class="pl-k">use</span> <span class="pl-v">Symfony</span>\<span class="pl-v">Component</span>\<span class="pl-v">Security</span>\<span class="pl-v">Core</span>\<span class="pl-v">User</span>\<span class="pl-v">UserInterface</span>;

<span class="pl-k">private</span> <span class="pl-s1"><span class="pl-c1">$</span>roleHierarchy</span>;

<span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__construct</span>(<span class="pl-smi"><span class="pl-smi">RoleHierarchyInterface</span></span> <span class="pl-s1"><span class="pl-c1">$</span>roleHierarchy</span> = <span class="pl-c1">null</span>)
{
    <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">roleHierarchy</span> = <span class="pl-s1"><span class="pl-c1">$</span>roleHierarchy</span>;
}

<span class="pl-k">private</span> <span class="pl-k">function</span> <span class="pl-en">userHasRole</span>(<span class="pl-smi"><span class="pl-smi">UserInterface</span></span> <span class="pl-s1"><span class="pl-c1">$</span>user</span>, <span class="pl-s1"><span class="pl-c1">$</span>roleName</span>)
{
    <span class="pl-k">if</span> (<span class="pl-c1">null</span> === <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">roleHierarchy</span>) {
        <span class="pl-k">return</span> in_array(<span class="pl-s1"><span class="pl-c1">$</span>roleName</span>, <span class="pl-s1"><span class="pl-c1">$</span>user</span>-&gt;<span class="pl-en">getRoles</span>(), <span class="pl-c1">true</span>);
    }

    <span class="pl-k">foreach</span> (<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">roleHierarchy</span>-&gt;<span class="pl-en">getReachableRoles</span>(<span class="pl-s1"><span class="pl-c1">$</span>user</span>-&gt;<span class="pl-en">getRoles</span>()) <span class="pl-k">as</span> <span class="pl-s1"><span class="pl-c1">$</span>role</span>) {
        <span class="pl-k">if</span> (<span class="pl-s1"><span class="pl-c1">$</span>roleName</span> === <span class="pl-s1"><span class="pl-c1">$</span>role</span>-&gt;<span class="pl-en">getRole</span>()) {
            <span class="pl-k">return</span> <span class="pl-c1">true</span>;
        }
    }

    <span class="pl-k">return</span> <span class="pl-c1">false</span>;
}</pre></div>
<h2 dir="auto">The solution</h2>
<p dir="auto">The obvious solution would be to provide a method such as <code class="notranslate">-&gt;hasRole(string $role_name)</code>. What do you think?</p>