web-dev-qa-db-fra.com

Symfony2 - vérifie si le fichier existe

J'ai une boucle dans le modèle Twig, qui renvoie plusieurs valeurs. Le plus important - un identifiant de mon entrée. Lorsque je n’utilisais ni moteur de template ni framework, j’utilisais simplement file_exists() dans la boucle. Maintenant, je n'arrive pas à trouver un moyen de le faire dans Twig.

Lorsque j'affiche l'avatar de l'utilisateur dans l'en-tête, j'utilise file_exists() dans le contrôleur, mais je le fais parce que je n'ai pas de boucle.

J'ai essayé defined dans Twig, mais cela ne m'aide pas. Des idées?

12
Tomek Buszewski

Si vous souhaitez vérifier l’existence d’un fichier qui n’est pas un modèle de brindille (la définition ne peut donc pas fonctionner), créez un service TwigExtension et ajoutez la fonction file_exists () à twig:

src/AppBundle/Twig/Extension/TwigExtension.php

<?php

namespace AppBundle\Twig\Extension;

class FileExtension extends \Twig_Extension
{

    /**
     * Return the functions registered as twig extensions
     * 
     * @return array
     */
    public function getFunctions()
    {
        return array(
            new Twig_SimpleFunction('file_exists', 'file_exists'),
        );
    }

    public function getName()
    {
        return 'app_file';
    }
}
?>

Enregistrez votre service:

src/AppBundle/Resources/config/services.yml

# ...

parameters:

    app.file.twig.extension.class: AppBundle\Twig\Extension\FileExtension

services:

    app.file.twig.extension:
        class: %app.file.twig.extension.class%
        tags:
            - { name: twig.extension }

Ça y est, vous pouvez maintenant utiliser file_exists () dans un modèle de brindille;)

Quelques template.twig:

{% if file_exists('/home/sybio/www/website/picture.jpg') %}
    The picture exists !
{% else %}
    Nope, Chuck testa !
{% endif %}

EDIT pour répondre à votre commentaire:

Pour utiliser file_exists (), vous devez spécifier le chemin absolu du fichier. Vous avez donc besoin du chemin absolu du répertoire Web. Pour ce faire, donnez accès au chemin Web dans vos modèles de brindille app/config/config.yml:

# ...

twig:
    globals:
        web_path: %web_path%

parameters:
    web_path: %kernel.root_dir%/../web

Vous pouvez maintenant obtenir le chemin physique complet du fichier dans un modèle de brindille:

{# Display: /home/sybio/www/website/web/img/games/3.jpg #}
{{ web_path~asset('img/games/'~item.getGame.id~'.jpg') }}

Vous pourrez donc vérifier si le fichier existe:

{% if file_exists(web_path~asset('img/games/'~item.getGame.id~'.jpg')) %}
31
Sybio

J'ai créé une fonction Twig qui est une extension des réponses trouvées à ce sujet. Ma fonction asset_if prend deux paramètres: le premier est le chemin d'accès de l'actif à afficher. Le deuxième paramètre est l'actif de secours, si le premier actif n'existe pas.

Créez votre fichier d'extension:

src/Showdates/FrontendBundle/Twig/Extension/ConditionalAssetExtension.php:

<?php

namespace Showdates\FrontendBundle\Twig\Extension;

use Symfony\Component\DependencyInjection\ContainerInterface;

class ConditionalAssetExtension extends \Twig_Extension
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Returns a list of functions to add to the existing list.
     *
     * @return array An array of functions
     */
    public function getFunctions()
    {
        return array(
            'asset_if' => new \Twig_Function_Method($this, 'asset_if'),
        );
    }

    /**
     * Get the path to an asset. If it does not exist, return the path to the
     * fallback path.
     * 
     * @param string $path the path to the asset to display
     * @param string $fallbackPath the path to the asset to return in case asset $path does not exist
     * @return string path
     */
    public function asset_if($path, $fallbackPath)
    {
        // Define the path to look for
        $pathToCheck = realpath($this->container->get('kernel')->getRootDir() . '/../web/') . '/' . $path;

        // If the path does not exist, return the fallback image
        if (!file_exists($pathToCheck))
        {
            return $this->container->get('templating.helper.assets')->getUrl($fallbackPath);
        }

        // Return the real image
        return $this->container->get('templating.helper.assets')->getUrl($path);
    }

    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    public function getName()
    {
       return 'asset_if';
    }
}

Enregistrez votre service (app/config/config.yml ou src/App/YourBundle/Resources/services.yml):

services:
    showdates.twig.asset_if_extension:
        class: Showdates\FrontendBundle\Twig\Extension\ConditionalAssetExtension
        arguments: ['@service_container']
        tags:
          - { name: twig.extension }

Maintenant, utilisez-le dans vos modèles comme ceci:

<img src="{{ asset_if('some/path/avatar_' ~ app.user.id, 'assets/default_avatar.png') }}" />
11
Rick Pastoor

J'ai eu le même problème que Tomek. J'ai utilisé la solution Sybio et apporté les modifications suivantes:

  1. app/config.yml => ajoutez "/" à la fin de chemin_Web

    parameters:
        web_path: %kernel.root_dir%/../web/
    
  2. Appelez file_exists sans "asset":

    {% if file_exists(web_path ~ 'img/games/'~item.getGame.id~'.jpg') %}
    

J'espère que cela t'aides.

3
Tobias

Pour améliorer la réponse de Sybio, Twig_simple_function n'existait pas pour ma version et rien ne fonctionne ici pour les images externes, par exemple. Donc, mon fichier d'extension de fichier est comme ceci:

namespace AppBundle\Twig\Extension;

class FileExtension extends \Twig_Extension
{
/**
 * {@inheritdoc}
 */

public function getName()
{
    return 'file';
}

public function getFunctions()
{
    return array(
        new \Twig_Function('checkUrl', array($this, 'checkUrl')),
    );
}

public function checkUrl($url)
{
    $headers=get_headers($url);
    return stripos($headers[0], "200 OK")?true:false;
}
0
Mr Sorbose

Voici ma solution, utilisant SF4, autowire et autoconfigure:

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Symfony\Component\Filesystem\Filesystem;

class FileExistsExtension extends AbstractExtension
{
    private $fileSystem;
    private $projectDir;

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

    public function getFunctions(): array
    {
        return [
            new TwigFunction('file_exists', [$this, 'fileExists']),
        ];
    }

    /**
     * @param string An absolute or relative to public folder path
     * 
     * @return bool True if file exists, false otherwise
     */
    public function fileExists(string $path): bool
    {
        if (!$this->fileSystem->isAbsolutePath($path)) {
            $path = "{$this->projectDir}/public/{$path}";
        }

        return $this->fileSystem->exists($path);
    }
}

Dans services.yaml:

services:
    App\Twig\FileExistsExtension:
        $projectDir: '%kernel.project_dir%'

Dans les modèles:

# Absolute path
{% if file_exists('/tmp') %}
# Relative to public folder path
{% if file_exists('tmp') %}

Je suis nouveau sur Symfony, donc tous les commentaires sont les bienvenus!

De plus, comme la question initiale concerne Symfony 2, peut-être que ma réponse n’est pas pertinente et que je ferais mieux de poser une nouvelle question et d’y répondre moi-même?

0
jo66

Ajoutez simplement un petit commentaire à la contribution de Sybio:

La classe Twig_Function_Function est obsolète depuis la version 1.12 et sera supprimée dans la version 2.0. Utilisez Twig_SimpleFunction à la place.

Nous devons changer la classe Twig_Function_Function by Twig_SimpleFunction:

<?php

namespace Gooandgoo\CoreBundle\Services\Extension;

class TwigExtension extends \Twig_Extension
{

    /**
     * Return the functions registered as twig extensions
     *
     * @return array
     */
    public function getFunctions()
    {
        return array(
            #'file_exists' => new \Twig_Function_Function('file_exists'), // Old class
            'file_exists' => new \Twig_SimpleFunction('file_exists', 'file_exists'), // New class
        );
    }

    public function getName()
    {
        return 'twig_extension';
    }
}

Le reste du code fonctionne toujours exactement comme dit Sybio.

0
Daniel Guerrero