Search code examples
phpsymfonyassetic

Assetic to include all files within sub directories


Just started using assectic in my Symfony2 project and have it working quite well but can't see a nice easy way to include all the javascript files within a bundle.

The structure for my AppBundle is

AppBundle
  - Controller
  - Resources
    - views
    - public
      - js
        - Model
          - User.js
        - View
          - Dashboard.js
        - Bundle.js
        - Router.js

My current code to compile this is

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

Which dumps out

<script src="/js/d356fea_part_1_Bundle_1.js"></script>
<script src="/js/d356fea_part_1_Router_2.js"></script>

So how can I get it to include all the javascript files in the sub folders?

Also is it possible to change the name of part_1? Would love that to say AppBundle during development.


Solution

  • After much research and playing this isn't possible with Assetic. I had to drop Assetic from the project for this reason and the fact it's too slow to update files which was causing problems for the front end developers.

    Not really a proper answer but as it's the only solution I could find in a short amount of time I ended up hacking a solution together.

    We now have a JSON config file like so:

    {
      "lib": {
        "cwd": {
          "vendor": "app/Resources/vendor"
        },
        "files": [
          "%vendor%/jquery/dist/jquery.min.js",
          "%vendor%/underscore/underscore-min.js",
          "%vendor%/backbone/backbone-min.js"    
        ]
      },
      "app": {
        "cwd": {
          "app": "app/Resources/public/js",
          "AppBundle": "src/AppBundle/Resources/public/js"
        },
        "files": [
          "%app%/*.js",
          "%AppBundle%/*.js"
        ]
      }
    }
    

    Then use grunt-contrib-symlink to symlink these directories into the web directory.

        symlink: {
            expanded: {
                files: function () {
                    var symlinks = [];
    
                    Object.keys(js).forEach(function (key) {
                        var file = js[key];
    
                        Object.keys(file.cwd).forEach(function (name) {
                            symlinks.push({
                                src: [file.cwd[name]],
                                dest: 'web/js/' + name
                            });
                        });
                    });
    
                    return symlinks;
                }()
            }
        },
    

    Then we have a simple twig function which will pull this apart and find all the filenames to include them each individually inside the development environment.

    class AssetService
    {
        protected $rootDir;
    
        public function __construct($rootDir)
        {
            $this->rootDir = $rootDir;;
        }
    
        public function getJavascriptFiles($ref)
        {
            $output = [];
            $data = json_decode(file_get_contents(realpath($this->rootDir . '/Resources/config/include.json')), true);
            $paths = [];
    
            foreach ($data[$ref]['cwd'] as $key => $path) {
                $paths['%' . $key . '%'] = $this->rootDir . '/../' . $path;
            }
    
            foreach ($data[$ref]['files'] as $file) {
                $output = array_merge($output, str_replace(
                    $paths,
                    array_keys($data[$ref]['cwd']),
                    $this->globRecursive(str_replace(array_keys($paths), $paths, $file), GLOB_NOCHECK)
                ));
            }
    
            return $output;
        }
    
        protected function globRecursive($pattern, $flags = 0)
        {
            $files = glob($pattern, $flags);
            foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
                $files = array_merge($files, $this->globRecursive($dir . '/' . basename($pattern)));
            }
            return $files;
        }
    }
    

    Then in development we have the output which looks something like this:

    <script src="/js/vendor/jquery/dist/jquery.min.js"></script>
    <script src="/js/vendor/underscore/underscore-min.js"></script>
    <script src="/js/vendor/backbone/backbone-min.js"></script>
    <script src="/js/AppBundle/Bundle.js"></script>
    <script src="/js/AppBundle/Router.js"></script>
    <script src="/js/AppBundle/Collection/Products.js"></script>
    <script src="/js/ProjectsBundle/Model/Project.js"></script>
    <script src="/js/AppBundle/View/Product/Index.js"></script>
    

    And after uglifying the files with Grunt using the same logic, in production we have:

    <script src="/js/lib.js"></script>
    <script src="/js/app.js"></script>
    

    Bit hacky, but it's instant updates and keeps the PHP production environment completely unaware of the front-end assets.