Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Problem

I have a CSS file with some paths in it (for images, fonts, etc.. url(..)).

My path structure is like this:

...
+-src/
| +-MyCompany/
|   +-MyBundle/
|     +-Resources/
|       +-assets/
|         +-css/
|           +-stylesheets...
+-web/
| +-images/
|   +-images...
...

I want to reference my images in the stylesheet.

First Solution

I changed all paths in the CSS file to absolute paths. This is no solution, as the app should (and has to!) be working in a subdirectory, too.

Second Solution

Use Assetic with filter="cssrewrite".

So I changed all my paths in my CSS file to

url("../../../../../..https://waybackassets.bk21.net/images/myimage.png")

to represent the actual path from my resources directory to the https://waybackassets.bk21.net/images directory. This does not work, since cssrewrite produces the following code:

url("../../Resources/assets/")

which is obviously the wrong path.

After assetic:dump this path is created, which is still wrong:

url("../../..https://waybackassets.bk21.net/images/myimage.png")

The twig code of Assetic:

{% stylesheets
    '@MyCompanyMyBundle/Resources/assets/css/*.css'
    filter="cssrewrite"
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}

Current (Third) Solution

Since all css files end up in https://waybackassets.bk21.net/css/stylexyz.css, I changed all paths in the css file to be relative:

url("../images/myimage.png")

This (bad) solution works, except in dev mode: The css path is /app_dev.php/css/stylexyz.css and therefore the image path resulting from this is /app_dev.php/images/myimage.png, which results in a NotFoundHttpException.

Is there a better and working solution?

share|improve this question
1  
I posted my solution here: stackoverflow.com/q/9501248/1146363 – Cerad Feb 29 '12 at 21:11
Does this actually solve the problem with the paths when using app_dev.php? – apfelbox Mar 1 '12 at 7:40
add comment (requires an account with 50 reputation)

5 Answers

up vote 52 down vote accepted

I have came across the very-very-same problem.

In short:

  • Willing to have original css in an "internal" dir (Resources/assets/css/a.css)
  • Willing to have the images in the "public" dir (Resources/public/images/devil.png)
  • Willing that twig takes that css, recompiles it into web/css/a.css and make it point the image in https://waybackassets.bk21.net/bundles/mynicebundle/images/devil.png

I have made a test with ALL possible (sane) combinations of the following:

  • @notation, relative notation
  • parse with cssrewrite, without it
  • css img background vs direct tag src= to the very same image than css
  • css parsed with assetic and also without parsing with assetic direct output
  • And all this multiplied by trying a "public dir" (as Resources/public/css) with the css and a "private" dir (as Resources/assets/css).

This gave me a total of 14 combinations on the same twig, and this route was launched from

  • "/app_dev.php/"
  • "/app.php/"
  • and "/"

thus givin 14 x 3 = 42 tests.

Additionally all this has been tested working in a subdirectory so no way to fool by giving absolute URLs because they would simply don't work.

The tests were two unnamed images and then divs named from 'a' to 'f' for the css built FROM the public folder and named 'g to 'l' for the ones built from the internal path.

I observed the following:

Only 3 of the 14 tests were shown adequately on the three urls. And NONE was from the "internal" folder (Resources/assets). It was a pre-requisite to have the spare css PUBLIC and then build with assetic FROM there.

These are the results:

  1. Result launched with /app_dev.php/ Result launched with /app_dev.php/

  2. Result launched with /app.php/ Result launched with /app.php/

  3. Result launched with / enter image description here

So... ONLY - The second image - Div B - Div C are the allowed syntaxes.

Here there is the TWIG code:

<html>
    <head>
            {% stylesheets 'bundles/commondirty/css_original/container.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: ABCDEF #}

            <link href="{{ '../bundles/commondirty/css_original/a.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( 'bundles/commondirty/css_original/b.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets 'bundles/commondirty/css_original/c.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets 'bundles/commondirty/css_original/d.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/e.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/f.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: GHIJKL #}

            <link href="{{ '../../src/Common/DirtyBundle/Resources/assets/css/g.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( '../src/Common/DirtyBundle/Resources/assets/css/h.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/i.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/j.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/k.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/l.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    </head>
    <body>
        <div class="container">
            <p>
                <img alt="Devil" src="../bundles/commondirty/images/devil.png">
                <img alt="Devil" src="{{ asset('bundles/commondirty/images/devil.png') }}">
            </p>
            <p>
                <div class="a">
                    A
                </div>
                <div class="b">
                    B
                </div>
                <div class="c">
                    C
                </div>
                <div class="d">
                    D
                </div>
                <div class="e">
                    E
                </div>
                <div class="f">
                    F
                </div>
            </p>
            <p>
                <div class="g">
                    G
                </div>
                <div class="h">
                    H
                </div>
                <div class="i">
                    I
                </div>
                <div class="j">
                    J
                </div>
                <div class="k">
                    K
                </div>
                <div class="l">
                    L
                </div>
            </p>
        </div>
    </body>
</html>

The container.css:

div.container
{
    border: 1px solid red;
    padding: 0px;
}

div.container img, div.container div 
{
    border: 1px solid green;
    padding: 5px;
    margin: 5px;
    width: 64px;
    height: 64px;
    display: inline-block;
    vertical-align: top;
}

And a.css, b.css, c.css, etc: all identical, just changing the color and the css selector.

.a
{
    background: red url('../images/devil.png');
}

The "directories" structure is:

Directories Directories

All this came because I did not want the individual original files exposed to the public, specially if I wanted to play with "less" filter or "sass" or similar... I did not want my "originals" published, only the compiled one.

But there are good news. If you don't want to have the "spare css" in the public directories... install them not with --symlink but really making a copy. Once "assetic" has built the compound css, you can DELETE the original css from the filesystem, and leave the images:

Compilation process Compilation process

Note I do this for the --env=prod environment.

Just a few final thoughts:

  • This desired behaviour can be achieved by having in the git or mercurial the images in "public" directory and the "css" in the "assets" directory. Ie: instead of having them in "public" as shown in the directories, imagine a, b, c... residing in the "assets" instead of "public", than have your installer/deployer (probably a bash script) to put the css temporarily inside the "public" dir before assets:install is executed, then assets:install, then assetic:dump, and then automating the removal of css from the public dir after assetic:dump has been executed. This would achive EXACTLY the behaviour desired in the question.

  • Another (unknown if possible) solution would be to explore if "assets:install" can only take "public" as the source or could also take "assets" as a source to publish. That would help when installed with the --symlink option when developing.

  • Additionally, if we are going to script the removal from the "public" dir, then, the need of storing them in a separate dir ("assets") disappears. They can live inside "public" in our version-control system as there will be dropped upon deploy to the public. This allows also for the --symlink usage.

BUT ANYWAY, CAUTION NOW: As now the originals are not there anymore (rm -Rf), there are only 2 solutions, not 3. The working div "B" does not work anymore as it was an asset() call assuming there was the original asset. Only "C" (the compiled one) will work.

So... there is ONLY a FINAL WINNER: Div "C" allows EXACTLY what it was asked in the topic: To be comppiled, respect the path to the images and do not expose the original source to the public.

Winner is C

Winner is C

Arrgg after spending a lot of time preparing images, I now cannot post images beause I'm new to stackoverflow and I still don't reach the minimum reputation. I've to post them as if they were links. If someone with enough reputation wants to take them and bring them inline, please do. Will be easier to read.

share|improve this answer
2  
Links to the images for the previous post: 1) Result launched with /app_dev.php/, 2) Result launched with /app.php/ link, 3) result launched with / link, 4) Directories link, 5) Compilation process link, 6) Who is the winner link – Xavi Montero Apr 24 '12 at 0:33
And if you want to add an image from another bundle, instead of using background-image: url('../images/devil.png'); use this background-image: url('../../../bundles/frontendlayout/images/devil.png'); – Xavi Montero Apr 24 '12 at 7:12
Also works combining "cssrewrite" with "less": {% stylesheets filter="cssrewrite,less" "bundles/frontendlayout/less/layout.less" %} <link href="{{ asset_url }}" rel="stylesheet" type="text/css" /> {% endstylesheets %} – Xavi Montero Apr 24 '12 at 8:24
Thank you for the very elaborate answer. I will give it a try and report back - but it sounds very promising, so far. – apfelbox Apr 24 '12 at 18:13
7  
one of the most precise answer ever, thanks – linuxatico May 18 '12 at 13:07
show 2 more commentsadd comment (requires an account with 50 reputation)

The cssrewrite filter is not compatible with the @bundle notation for now. So you have two choices :

  • reference the CSS files in the web folder (after: console assets:install --symlink web)
{% stylesheets '/bundles/myCompany/css/*." filter="cssrewrite" %}
  • use the cssembed filter to embed images in the CSS like this.
{% stylesheets '@MyCompanyMyBundle/Resources/assets/css/*.css' filter="cssembed" %}
share|improve this answer
Thank you for your comment. The second solution sounds quite good if you only have rather small images. I would not feel comfortable to put some 100k+ images in the CSS file, though. – apfelbox Apr 24 '12 at 18:15
add comment (requires an account with 50 reputation)

I'll post what worked for me, thanks to @xavi-montero.

Put your css in your bundle's Resource/public/css dir, and your images in say Resource/public/img

Change assetic paths to this form 'bundles/mybundle/css/*.css', in your layout.

In config.yml, add css_rewrite rule to assetic:

assetic:
    filters:
        cssrewrite:
            apply_to: "\.css$"

Now install assets and compile with assetic

$ rm -r app/cache/* # just in case
$ php app/console install:assets --symlink
$ php app/console assetic:dump --env=prod

This is good enough for the development box, and --symlink is useful so you don't have to reinstall your assets (eg: you add a new image) when you enter through app_dev.php.

For the production server, I just removed the '--symlink' option (in my deployment script), and added this command at the end:

$ rm -r web/bundles/*/css web/bundles/*/js # all this is already compiled, we don't need the originals

All done. With this, you can use paths like this in your .css files: ../img/picture.jpeg

share|improve this answer
add comment (requires an account with 50 reputation)

If it can help someone, we have struggled a lot with Assetic and we are now doing the following in dev mode:

  • setup like this

http://symfony.com/doc/current/cookbook/assetic/asset_management.html#dumping-asset-files-in-the-dev-environment

so in config_dev.yml, we have commented

#assetic:
#    use_controller: true

and in routing_dev.yml

#_assetic:
#    resource: .
#    type:     assetic
  • specify the url as absolute from the web root for example: background-image: url("/bundles/core/dynatree/skins/skin/vline.gif"); Note: our vhost web root is pointing on web/

  • no usage of cssrewrite filter

Best regards, Christophe

share|improve this answer
This is a valid solution, but only if you will never serve the files from a subdirectory, for example: http://example.org/sub/. – apfelbox Aug 22 '12 at 22:31
add comment (requires an account with 50 reputation)

Put your images in the path Resources/public/images within the bundle and then use the CLI command assets:install.

This will publish your image assets to web/bundles/< BundleName >/images and will publish your finished CSS to web/bundles/< BundleName >/css.

The relative path between CSS and images should be the same here as it was in your bundle.

When using relative paths to global images that you manually add to the web directory assume that your path is relative to web/bundles/< BundleName >/css.

Alternatively you could use the cssrewrite filter to dynamically rewrite your url() paths in the CSS.

share|improve this answer
This does not solve the problem with app_dev.php – apfelbox Mar 1 '12 at 22:31
Even when working with app_dev.php you still need to publish the assets – Hades Mar 3 '12 at 0:13
I did. So my CSS file is served by the path /app_dev.php/css/style.css. The assets inside the CSS are linked using url("../images/someimage.png"), so the actual request for the image ends up with /app_dev.php/images/someimage.png, which results in a NotFoundHttpException. – apfelbox Mar 3 '12 at 0:15
The path should be /app_dev.php/bundles/MyBundleName/images/someimage.png if you've done assets:install and assetic:dump ... try adding debug=false to the stylesheets twig tag.. that might help – Hades Mar 4 '12 at 12:15
Ok, so I have made the suggested changes. If I now try to request an image (or a css file) via /app_dev.php/bundles/MyBundleName/images/someimage.png I still get an NotFoundHttpException. /bundles/MyBundleName/images/someimage.png (without app_dev.php works without errors). – apfelbox Mar 5 '12 at 10:22
add comment (requires an account with 50 reputation)

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.