Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Image Preview on the Form

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Let's render a thumbnail on the show page too. The size here is restricted to a width of 250. Copy the first filter, paste, and call this one, how about, squared_thumbnail_medium. Set the size to 500 by 500.

liip_imagine:
... lines 2 - 5
filter_sets:
... lines 7 - 16
squared_thumbnail_medium:
filters:
thumbnail:
size: [500, 500]
mode: outbound
allow_upscale: true
... lines 23 - 49

Copy the name and this time go into show.html.twig. Add the |imagine_filter() and paste!

... lines 1 - 4
{% block content_body %}
<div class="row">
<div class="col-sm-12">
<img class="show-article-img" src="{{ uploaded_asset(article.imagePath)|imagine_filter('squared_thumbnail_medium') }}">
... lines 9 - 25
</div>
</div>
... lines 28 - 78
{% endblock %}
... lines 80 - 86

Reload! It works! The first time it has the resolve in the URL and is handled by a Symfony route & controller. The second time, it points directly to the file that was just saved. Awesome!

Adding an Image Preview to the Form

While we're kicking butt, go back to the article admin section and click to edit the article we've been working on. Hmm, it's not obvious that this article has an image attached... or what it looks like. We need a little image thumbnail next to this field.

We got this. Open the form template templates/article_admin/_form.html.twig. Let's think: to render an image, we could create a form theme that automatically makes the form_row() function render an image preview for file fields. That's cool. Or, we can keep it simple and do it right here.

Create a <div class="row"></div> and another <div class="col-sm-9"><div> inside to set up a mini grid. Move the file field here. Now add a div with class="col-sm-3": this is where we'll render the image... if there is one.

{{ form_start(articleForm) }}
... lines 2 - 5
<div class="row">
<div class="col-sm-9">
{{ form_row(articleForm.imageFile, {
attr: {
'placeholder': 'Select an article image'
}
}) }}
</div>
<div class="col-sm-3">
... lines 15 - 17
</div>
</div>
... lines 20 - 38
{{ form_end(articleForm) }}

To do that, we need the Article object. Copy the image path logic from the homepage and then go find the controller for the admin section: ArticleAdminController. When we render the template - this is in the new() action - we're only passing the form variable. In edit(), we're doing the same thing. We could add an article variable here - that's a fine option. But, we don't need to.

Back in the template, we can say {% if articleForm.vars.data %} - that will be the Article object - then .imageFilename. If we have an image filename, print <img src="{{ }}"> and paste. Replace article with articleForm.vars.data. And yes, I should add an alt attribute - please do that! Set the height to 100, because the actual thumbnail is 200 for quality reasons.

{{ form_start(articleForm) }}
... lines 2 - 5
<div class="row">
... lines 7 - 13
<div class="col-sm-3">
{% if articleForm.vars.data.imageFilename %}
<img src="{{ uploaded_asset(articleForm.vars.data.imagePath)|imagine_filter('squared_thumbnail_small') }}" height="100">
{% endif %}
</div>
</div>
... lines 20 - 38
{{ form_end(articleForm) }}

Try it! Refresh and... yes! To make sure we didn't break anything, try creating a new article. Whoops... we broke something!

Impossible to access attribute imageFilename on a null variable

Ah, we need to be careful: articleForm.vars.data may be null on a "new" form - it depends how you set it up. The easiest fix is to add |default. It's kinda weird... when you add |default, it suppresses the error and just returns null if there were any problems, which, for the if statement, is the same as false. It looks weird, but works great. Try it. All better.

{{ form_start(articleForm) }}
... lines 2 - 5
<div class="row">
... lines 7 - 13
<div class="col-sm-3">
{% if articleForm.vars.data.imageFilename|default %}
<img src="{{ uploaded_asset(articleForm.vars.data.imagePath)|imagine_filter('squared_thumbnail_small') }}" height="100">
{% endif %}
</div>
</div>
... lines 20 - 38
{{ form_end(articleForm) }}

Next, we have a real upload system (yay!) but our article data fixtures are broken: they're just setting imageFilename to a random filename that won't actually exist in the uploads/ directory. How can we fix that? By using our file upload system inside the fixtures! Well, at least, sort of.

Leave a comment!

24
Login or Register to join the conversation
Jean-tilapin Avatar
Jean-tilapin Avatar Jean-tilapin | posted 1 year ago

Hello there, SymfonyCasts. A little security question, please.

Someone asked me to build him a very small, very simple but very secure "cloud" service. I already built him his website with Symfony, which is hosted by a regular company with standards features (and he is very happy about it \o/). This person has very little knowledge in computer and can't use a filezilla-like app to configure a ftps connexion. What he wants is to upload a file (from his computer or his phone) and get a download link that he can send to anyone he wants (his accountant, mostly, but I guess he might also use that cloud service for his personal use).

How secure would it be use your screencast to build him what he asks? To store his private data on a "src/private" directory? Would it be unreachable by anyone un-authorized, thanks to Symfony?

What do you think? Is it possible and safe? If yes, are there already recipes I could use?

Thank you.

Reply
Ali_M Avatar

Hi, I followed your tutorial and managed to get everything working. I recently upgraded the symfony version from 5.2 to 5.3 and got rid of all the deprecations. Then I ran composer update and got - Upgrading liip/imagine-bundle (2.6.0 => 2.7.3). Now, I am having 3 new deprecation warnings, two of which belong to the liip.

21:28:58
php User Deprecated: The Liip\ImagineBundle\Templating\FilterExtension class is deprecated since version 2.7 and will be removed in 3.0; configure "twig_mode" to "lazy" instead.
Show context Show trace
21:28:58
php User Deprecated: The Liip\ImagineBundle\Templating\FilterTrait trait is deprecated since version 2.7 and will be removed in 3.0; use Twig instead.
Show context Show trace
21:28:58
n/a The "Symfony\Bridge\Doctrine\Logger\DbalLogger" class implements "Doctrine\DBAL\Logging\SQLLogger" that is deprecated Use {@link \Doctrine\DBAL\Logging\Middleware} or implement {@link \Doctrine\DBAL\Driver\Middleware} instead.
Show context Show trace

Any help is appreciated!

Reply
sadikoff Avatar sadikoff | SFCASTS | Ali_M | posted 1 year ago | edited

Hey Ali

Deprecations are not issues =) But if you are a perfectionist and want to fix everything at all, then you should do more =)

Liip bundle is easy fix, just add to configuration


liip_imagine:
    twig:
        mode: lazy

probably it will fix both deprecations.

For doctrine, I don't have a solution it's internal and will gone with some other updates

Cheers!

Reply
Ali_M Avatar
Ali_M Avatar Ali_M | sadikoff | posted 1 year ago | edited

Hi sadikoff , I was just about to update my question and provide my solution to the issue, when I saw you already mentioned it. php bin/console debug:config LiipImagineBundle showed me that I was having the twig mode using the legacy. Changing it to the lazy mode fixed both deprecation messages. Thanks! :)

Reply

Awesome! I'm happy that you found solution by yourself =)

Cheers!

Reply
Default user avatar
Default user avatar Fabien Hanna | posted 1 year ago

Hi,
I followed all the steps given. However, when I refresh, no media folder is being created in the uploads por any other place.
Could you please advise why that might happen?
Thank you.

Reply

Hey Fabien

That's a bit odd. Is it possible that the file it's been generated in a different spot?
could you check the logs just to see if there is a hint of what's going on?
Another thing you can do is to check the docs here https://symfony.com/bundles... just to compare your config

Cheers!

Reply
Charlotte M. Avatar
Charlotte M. Avatar Charlotte M. | posted 3 years ago | edited

I am getting the following error when I install the liip/imagine-bundle. I can get around this error by installing liip/imagine-bundle 2.2.0 instead of 2.3.0 but then I run into the error reported by others of "Unexpected "apply" tag (expecting closing tag for the "block" tag defined near line 2)." in the edit article page

`composer require liip/imagine-bundle
Using version ^2.3 for liip/imagine-bundle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Restricting packages listed in "symfony/symfony" to "4.2.*"
Your requirements could not be resolved to an installable set of packages.

Problem 1

- Installation request for liip/imagine-bundle ^2.3 -> satisfiable by liip/imagine-bundle[2.3.0].
- liip/imagine-bundle 2.3.0 requires symfony/asset ^3.4|^4.3|^5.0 -> no matching package found.

Potential causes:

Read <https://getcomposer.org/doc/articles/troubleshooting.md&gt; for further common problems.

Installation failed, reverting ./composer.json to its original content.`

Reply

Hey Charlotte,

Yes, from the error you can see that to be able to install liip/imagine-bundle v2.3.0 you will need to be on Symfony 4.3 or higher at least. As I see from the output, your Symfony version is 4.2. So, the only solution to install the version you want is: update your current Symfony version at least to version 4.3. Otherwise, you need to stay on v2.2.x

Cheers!

Reply
Charlotte M. Avatar
Charlotte M. Avatar Charlotte M. | Victor | posted 3 years ago

Thanks. When I download the tutorial from scratch it is setup via composer.json to be limited to 4.2. Is this tutorial compatible with 4.3?

Reply

Hey Charlotte,

Yes, it should be compatible, Symfony has "no BC breaks" promise in minor releases, so up to 4.4 it should work fine. Though, new versions of other libraries (not Symfony official packages) may have their own release strategy, so those package upgrades may lead to some BC breaks, you would need to check their changelogs to make sure it will work. And yes, if you want a newer version of Symfony instead of that we locked in composer.json/composer.lock files - you need to do some manual steps to upgrade it. Btw, in case you're interesting in upgrading - we have a separate screencast about it here:
https://symfonycasts.com/sc...

I hope this helps!

Cheers!

Reply
mr_d Avatar
mr_d Avatar mr_d | posted 3 years ago | edited

I am also getting this error on the edit page after installing liip\imagine bundle:
Unexpected "apply" tag (expecting closing tag for the "block" tag defined near line 2).

Started with the start project and followed the tutorial exactly as described.
even without any configurations on the imagine bundle the error is still there.

Any ideas?

Reply
mr_d Avatar
mr_d Avatar mr_d | mr_d | posted 3 years ago | edited

Ok.
For some reason if I move the LiipImagineBundle bundle before the TwigBundle in bundles.php - the error is gone.

<br />...<br />Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], <br />Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],<br />Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],<br />Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],<br />...<br />

Reply

Hey mr_d!

Wow, that is VERY odd - the bundle order should almost never matter :/. What version of PHP are you on? The downloaded start code works fine for me - so the PHP version is one of the only things I can think of.

Cheers!

Reply
mr_d Avatar
mr_d Avatar mr_d | weaverryan | posted 3 years ago | edited

Hi weaverryan
Here are the details:
Win10 Pro x64 1809
PHP 7.3.11

But as far I see it's the bundle and imagine library that are causing the issue.
Check this video that i made few minutes ago:
https://youtu.be/LakFtYcRtEs

Reply

Hey mr_d!

AWESOME debugging and video. SUPER helpful. Something strange is definitely happening. I can't explain why swapping the bundle lines fixes the problem. However, I do recognize the issue and I believe this PR should fix it: https://github.com/liip/LiipImagineBundle/pull/1249

When you downgraded the bundle, you were downgrading to a version before they started using the apply filter. And the twig/twig version we ship with this bundle does not come with apply

So, the short answer is that: downgrading to the old version of the bundle is the correct solution. When/if the PR is accepted, when you required LiipImagineBundle, you would then get that older version anyways (I believe) because composer would recognize that it is the only one compatible with the version of Twig. Of course, you can also upgrade twig/twig. But tutorial code should work out-of-the-box ;).

Cheers!

1 Reply
mr_d Avatar
mr_d Avatar mr_d | weaverryan | posted 3 years ago | edited

Great!!
michellesanver merged 1 commit into liip:master from weaverryan:patch-1 2 hours ago

Reply
Paul-S Avatar

Okay I fixed the error by replacing the {% apply spaceless %} tag in the template with

{% block spaceless %}

Reply

Hey Paul S.

Interesting situation. However it's not a fix! Can you provide some information for investigation of this error?
- does this error happens on course code?
- exact version of LiipImagineBundle installed on your project?
- installed php and symfony version?

Cheers!

Reply
Paul-S Avatar

Hi Vladimir Sadicov
I downloaded the source code to follow along with the tutorial.
My setup is as follows:

PHP 7.2 although the composer.json file that came with the download has PHP 7.1.3 in its confog settings
Symfony 4.2.3
I installed the LiipImagineBundle 2.2 looking at my composer.json file.

The liip_imagine.yaml file is also different from the tutorial as it only has the following pre-coded:

*****************************************************************************

# See dos how to configure the bundle: https://symfony.com/doc/cur...
liip_imagine:
# valid drivers options include "gd" or "gmagick" or "imagick"
driver: "gd"

*******************************************************************************

Only by replacing 'apply' with 'block' was I able to proceed with the tutorial

Reply
Paul-S Avatar
Paul-S Avatar Paul-S | Paul-S | posted 3 years ago | edited

Paul S.

The error was generated from the following Twig template in the Liip bundle: vendor/liip/imagine-bundle/Resources/views/Form/form_div_layout.html.twig

On lines 2 & 18

Reply

Hey Paul S.

Sorry for so long answer, but Thanks to Ryan and another thread here, they figured out what's wrong here and it looks like fixed now. You should remove liip bundle and install it again, and it should work!

Cheers!

Reply
Paul-S Avatar

Unexpected "apply" tag (expecting closing tag for the "block" tag defined near line 2).

Reply
Paul-S Avatar
Paul-S Avatar Paul-S | posted 3 years ago | edited

I keep getting this error:

`Twig_Error_Syntax

        in
        \vendor/liip/imagine-bundle/Resources/views/Form/form_div_layout.html.twig            (line 2)

{% block liip_imagine_image_widget %}

{% apply spaceless %}
    {% if image_path %}
        <div>
            {% if link_url %}
                <a href="{{ link_filter ? link_url|imagine_filter(link_filter): link_url }}" {% for attrname, attrvalue in link_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}>
            {% endif %}`
Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built on Symfony 4 but works great in Symfony 5!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "aws/aws-sdk-php": "^3.87", // 3.87.10
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
        "knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
        "knplabs/knp-time-bundle": "^1.8", // 1.9.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.22
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "liip/imagine-bundle": "^2.1", // 2.1.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.1.0
        "oneup/flysystem-bundle": "^3.0", // 3.0.3
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.2.4
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.2.3
        "symfony/console": "^4.0", // v4.2.3
        "symfony/flex": "^1.9", // v1.17.6
        "symfony/form": "^4.0", // v4.2.3
        "symfony/framework-bundle": "^4.0", // v4.2.3
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.2.3
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "^4.0", // v4.2.3
        "symfony/validator": "^4.0", // v4.2.3
        "symfony/web-server-bundle": "^4.0", // v4.2.3
        "symfony/yaml": "^4.0", // v4.2.3
        "twig/extensions": "^1.5" // v1.5.4
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.1.0
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/debug-bundle": "^3.3|^4.0", // v4.2.3
        "symfony/dotenv": "^4.0", // v4.2.3
        "symfony/maker-bundle": "^1.0", // v1.11.3
        "symfony/monolog-bundle": "^3.0", // v3.3.1
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.2.3
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "^3.3|^4.0" // v4.2.3
    }
}
userVoice