Haehnchen / idea-php-symfony2-plugin

IntelliJ IDEA / PhpStorm Symfony Plugin
https://plugins.jetbrains.com/plugin/7219
MIT License
911 stars 137 forks source link

ide-twig.json #2384

Closed landsman closed 4 months ago

landsman commented 4 months ago

Hi, can you please help me with correct syntax of this file? I don't get it from an example.

I have this folder structure:

src/Modules/Warehouse/Stocktaking/View/index.html.twig 

Which is working just fine in terms of configuration of the project. So I want to resolve IntelliJ highlighter and code, file navigation. From what I saw I can define my aliases with paths and IDE should pick it up automatically without any custom settings, is that right?

Is this syntax correct?

This is my generated file:

{
    "namespaces": [
        {
            "namespace": "@Warehouse",
            "path": "%kernel.project_dir%/src/Modules/Warehouse"
        },
        {
            "namespace": "@Warehouse/Stocktaking",
            "path": "%kernel.project_dir%/src/Modules/Warehouse/Stocktaking"
        },
        {
            "namespace": "@Warehouse/Stocktaking/Crud",
            "path": "%kernel.project_dir%/src/Modules/Warehouse/Stocktaking/Crud"
        },
        {
            "namespace": "@Warehouse/Stocktaking/Crud/View",
            "path": "%kernel.project_dir%/src/Modules/Warehouse/Stocktaking/Crud/View"
        }
    ]
}

Problem:

Screenshot 2024-05-31 at 13 58 33

landsman commented 4 months ago

So backslashes was a problem I see.

This is working:

{
    "namespaces": [
        {
            "namespace": "Warehouse_Stocktaking_Crud_View",
            "path": "/src/Modules/Warehouse/Stocktaking/Crud/View"
        }
    ]
}

Usage:

    /**
     * @Route("/", name="warehouse_stocktaking_index", methods={"GET"})
     */
    public function index(): Response
    {
        return $this->render('@Warehouse_Stocktaking_Crud_View/index.html.twig', [
            'who' => 'world',
        ]);
    }

Here is the code for automatic generation:

<?php

namespace App\Service;

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

/**
 * Loads Twig paths for our custom modules.
 */
class TwigDynamicPathLoader
{
    private ParameterBagInterface $parameterBag;
    private Environment $twig;
    private KernelInterface $kernel;
    private bool $pathsLoaded = false;

    public function __construct(ParameterBagInterface $parameterBag, Environment $twig, KernelInterface $kernel)
    {
        $this->parameterBag = $parameterBag;
        $this->twig = $twig;
        $this->kernel = $kernel;
    }

    public function loadPaths(): void
    {
        if ($this->pathsLoaded) {
            return;
        }

        $modulesDir = $this->parameterBag->get('kernel.project_dir') . '/src/Modules';
        $loader = $this->twig->getLoader();

        if (!$loader instanceof FilesystemLoader) {
            throw new \LogicException('Twig loader is not an instance of FilesystemLoader.');
        }

        $directoryIterator = new \RecursiveDirectoryIterator($modulesDir, \FilesystemIterator::SKIP_DOTS);
        $iterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);

        // log
        $pathsAdded = [];

        foreach ($iterator as $file) {
            if ($file->isDir()) {
                $path = $file->getPathname();
                $relativePath = str_replace($modulesDir . DIRECTORY_SEPARATOR, '', $path);

                // usage of the alias
                $alias = str_replace('/', '_', $relativePath);

                // Check for .twig files in the directory
                $hasTwigFiles = false;
                $files = new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS);
                foreach ($files as $fileInfo) {
                    if ($fileInfo->isFile() && 'twig' === $fileInfo->getExtension()) {
                        $hasTwigFiles = true;
                        break;
                    }
                }

                if ($hasTwigFiles) {
                    $loader->addPath($path, $alias);
                    $relativeProjectPath = str_replace($this->parameterBag->get('kernel.project_dir'), '', $path);
                    $pathsAdded[] = [
                        'namespace' => $alias,
                        'path' => $relativeProjectPath,
                    ];
                }
            }
        }

        $this->pathsLoaded = true;

        // Run this code only in the dev environment
        if ('dev' === $this->kernel->getEnvironment()) {
            // Final dump of paths added with a label
            dump(['label' => 'Twig Paths from Modules', 'data' => $pathsAdded]);

            // Generate JSON for IDE
            $this->generateJsonForIde($pathsAdded);
        }
    }

    /**
     * Generate a JSON file to help the IDE recognize Twig namespaces.
     */
    private function generateJsonForIde(array $paths): void
    {
        $jsonFile = $this->parameterBag->get('kernel.project_dir') . '/ide-twig.json';
        $jsonContent = [
            'namespaces' => $paths,
        ];

        file_put_contents($jsonFile, json_encode($jsonContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    }
}