Take a look at @import in less-files for getting lastModified #151

Closed
rejinka opened this Issue Jan 8, 2013 · 3 comments

3 participants

@rejinka

Following situation: I include a bootstrap.less, which looks like

@import "variables.less"
@import "layout.less"

If i change anything in variables.less or layout.less, the assetic controller won't regenerate the css file, because the only lastModified, which is interesting for it, is the one of bootstrap.less. As you see, it can be interesting to look on the lastModified property of other files, too.

So i wrote some code, to get the wished behavior:

<?php

namespace UPB\NuctahCoreBundle\Util\Assetic;

use \Symfony\Bundle\AsseticBundle\Factory\AssetFactory as BaseAssetFactory;

use \UPB\NuctahCoreBundle\Util\Assetic\Asset\LessFileAsset;


class AssetFactory extends BaseAssetFactory
{
    protected function createFileAsset($source, $root = null, $path = null, $vars)
    {
        if (preg_match('/\.less$/', $source))
            return new LessFileAsset($source, array(), $root, $path, $vars);

        return parent::createFileAsset($source, $root, $path, $vars);
    }
}

and

<?php

namespace UPB\NuctahCoreBundle\Util\Assetic\Asset;

use \Assetic\Asset\FileAsset;

use \NajiDev\Common\Helper\StringHelper;


class LessFileAsset extends FileAsset
{
    public function getLastModified()
    {
        // this is our regular expression for finding import statements.
        $importExpression = '/@import "(.*)";/';

        $filesToDo = array();
        $filesDone = array();

        $filesToDo[] = $this->getSourceRoot() . '/' . $this->getSourcePath();
        while (!empty($filesToDo))
        {
            $filename = array_pop($filesToDo);
            $filename = realpath($filename);

            // if we handled this file, jump to next one
            if (in_array($filename, $filesDone))
                continue;

            // fetch all import statements
            if (preg_match_all($importExpression, file_get_contents($filename), $matches))
            {
                foreach ($matches[1] as $file)
                {
                    // cut a possible ".less" and add it again
                    // possible: @import "variables" and @import "variables.less"
                    $file =   StringHelper::trimStringRight($file, '.less') . '.less';

                    if (false !== $file = realpath(dirname($filename) . '/' . $file))
                        $filesToDo[] = $file;
                }
            }

            $filesDone[] = $filename;
        }

        $lastModified = 0;
        foreach ($filesDone as $file)
            if ($lastModified < $newLastModified = filemtime($file))
                $lastModified = $newLastModified;

        return $lastModified;
    }
}

Another class, which i used in LessFileAsset:

<?php

namespace NajiDev\Common\Helper;

use \NajiDev\Common\Exception\InvalidArgumentException;


class StringHelper
{
    /**
      * Strip a string from the end of a string
      *
      * @param string $str      the input string
      * @param string $remove   string to remove
      *
      * @throws \NajiDev\Common\Exception\InvalidArgumentException
      * @return string the modified string
      */
    public static function trimStringRight($str, $remove)
    {
        if (!is_string($str))
            throw new InvalidArgumentException('$str has to be a string');

        if (!is_string($remove))
            throw new InvalidArgumentException('$remove has to be a string');

        $len    = strlen($remove);
        $offset = strlen($str) - $len;

        while(0 < $offset && strpos($str, $remove, $offset) === $offset)
        {
            $str    = substr($str, 0, $offset);
            $offset = strlen($str)-$len;
        }

        return $str;
    }
}

If you have any suggestions for modifing my code, please let me know. I would then create a pull request (and also modify the code to match your code guideline)

@stof
Symfony member

Having some stuff specific to less in the asset factory does not make sense (the asset factory should not be responsible for it, and the issue is not limited to less).

Please see kriswallsmith/assetic#79 where the discussion about the issue happens

@rjmunro

@stof This bug is still open - does that mean the problem has still not been fixed? kriswallsmith/assetic#79 doesn't mention if the less filter specifically has been fixed, it just lays the groundwork so it could be. Is there another bug to track the less filter (apart from this one)?

What is the recommended workaround?

@stof
Symfony member

the Lessfilter implements getChildren in the latest dev version of assetic

@stof stof closed this Oct 4, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment