Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$imagineCacheManager->resolve($image, $filter) doesn't generate file in controller #1567

Closed
tacman opened this issue Feb 22, 2024 · 9 comments

Comments

@tacman
Copy link
Contributor

tacman commented Feb 22, 2024

Is your feature request related to a problem? Please describe.

I want resolve an image immediately after upload in my controller, so I can send it in an email.

I've read #784, but it seems the solution is to either trigger the liip:imagine:cache:resolve command, or to fetch the resolve image.

Neither are practical, the resolve image goes through a proxy, and I don't want to spawn a new process just to resolve an image.

  • A clear and concise description of what you want to happen.
        $filter = 'squared_thumbnail_medium';
        $image = $submission->getImageName();

        $browserPath = $imagineCacheManager->getBrowserPath($image, $filter);
        $resolvedPath = $imagineCacheManager->resolve($image, $filter);

        // perhaps there's a way to get this from the cache manager?
        $path = $projectDir . '/public/media/cache/' . $filter . '/' . $image;
        assert(file_exists($path), $path);

Why does the assert fail? Obviously, it fails because the file doesn't exist.

The code from the resolve command is

            if ($this->filterService->warmUpCache($image, $filter, null, $forced)) {
                $this->io->status('resolved', 'green');
            } else {
                $this->io->status('cached', 'white');
            }

            $this->io->line(sprintf(' %s', $this->cacheManager->resolve($image, $filter)));

I tried adding this to my controller, and injecting the filterservice, but it fails with not being able to find the service, plus it feels hackish.

    public function __construct(
        #[Autowire('%liip_imagine.service.filter%')] private FilterService $filterService,

In short, why doesn't resolve() actually resolve the image, that is, create the cached file?

FWIW, I'm using Flysystem with S3 for the source images, and they work fine in twig with the normal commands.

Thanks!

@dbu
Copy link
Member

dbu commented Feb 23, 2024

i hope we can do some radical refactorings for version 3, the naming on the api is often not clear at all.

afaik CacheManager::resolve gives you the path for the image (either the cached one, or the one going to the controller to generate the file). it does not generate the file then and there.

i think for now, injecting the filter service is the right way. you will want #[Autowire('liip_imagine.service.filter')] (without the %, the % tells that this would be a variable name, but you specify the service name directly)

if you have messaging, it would make sense to send a message similar to the warmup message, but with your handler in addition to generating the cache also sends the email. otherwise the upload controller will block until the email is sent.

@ytilotti
Copy link

ytilotti commented Mar 17, 2024

@dbu with this code:

use Liip\ImagineBundle\Service\FilterService;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

public function __construct(
    #[Autowire('liip_imagine.service.filter')] private FilterService $filterService,
) {
}

I have the error message: ...($filterService) must be of type Liip\\ImagineBundle\\Service\\FilterService, string given.
Is it normal?

@tacman
Copy link
Contributor Author

tacman commented May 5, 2024

[Autowire('liip_imagine.service.filter')] (without the %)

simply injects a string and throws this error:

App\EventListener\VichUploadListener::__construct(): Argument #3 ($filterService) must be of type Liip\ImagineBundle\Service\FilterService, string given, called in /home/tac/g/sites/voxitour/var/cache/dev/ContainerIFN7RuA/getVichUploadListenerService.php on line 23

The service is marked as private, and when I tried to set it to public it needs the rest of the definition.

So I'm left with dispatching a message or injecting the kernel, finding the liip resolve application and calling it, or injecting the Process component and processing it using a separate thread.

It seems like it would be so natural for ->resolve to take an argument like "bool $actuallyResolve) that would generating the images and then always return /media/cache/whatever.

My application uses javascript to generate the link tags and doesn't have access to the twig helper function that generates either the resolve or cache link. So I want the upload service to create the thumbnails during upload, and it's really hard to do that.

@tacman
Copy link
Contributor Author

tacman commented May 5, 2024

Wahoo, I think I have it working within the upload service. I'll document it here, and perhaps there's a better way.

# services.yaml
    Liip\ImagineBundle\Service\FilterService:
        public: true
        autowire: true
        autoconfigure: true
        arguments:
            $webpGenerate: false
            $webpOptions: []

    liip_imagine.service.filter:
        alias: Liip\ImagineBundle\Service\FilterService
        public: true
    public function __construct(
        private CacheManager          $cacheManager,
        private FilterService $filterService,

    )
// then call it

        foreach (['squared_thumbnail_tiny',
                     'squared_thumbnail_small','squared_thumbnail_medium'] as $filter) {
            $result = $this->filterService->warmUpCache($target, $filter, null);
            $url = $this->cacheManager->resolve($target, $filter);
            dump($result, $url);
        }

@dbu
Copy link
Member

dbu commented May 6, 2024

@ytilotti according to https://symfony.com/blog/new-in-symfony-6-1-service-autowiring-attributes you should do

    #[Autowire(service: 'liip_imagine.service.filter')] private FilterService $filterService,

to let symfony know this is a service.

that said, we should add a service alias for the FilterService so that the magic autowiring of symfony can work.

@tacman why do you need to make the service public? when you configure your service, you can specify to inject the liip_imagine.service.filter. that works with private services, only if you inject the container and want to pull the service from the container does it need to be public.

@tacman
Copy link
Contributor Author

tacman commented May 6, 2024

My use case is so basic. I just want to generate the thumbnails at the time the image is uploaded.

Currently there are just two ways to generate thumbnails, as the resolve method doesn't do the generation, it creates a link that will do the generation if necessary when called.

  • run the console command to generate the thumbnails
  • fetch the link created by resolve()

Fetching the link is complicated when running a proxy like the Symfony CLI. Running the command is messy from a service because you start a new process.

The solution of adding the word service: before the service name appears to work. Thank you. I guess I can close this issue, and I'll tweak the docs to reflect how to do this.

@tacman tacman closed this as completed May 6, 2024
@tacman
Copy link
Contributor Author

tacman commented May 6, 2024

why do you need to make the service public?

I don't. But the previous instructions to inject it weren't correct, so I was just hacking until I could.

@dbu
Copy link
Member

dbu commented May 7, 2024

generating the images is slow, which is why its not done immediately but delayed to the controller. the recommended way if you don't want to generate the images only on demand would be to use the message worker

by injecting the filter, you can however indeed do it in the controller, blocking the request, if you must generate the thumbnail before responding. i hope we find the time eventually for a severe cleanup of the whole bundle with simple and clear names for the different options (getting the controller url versus generating an image and getting the url to the specific image)

@ytilotti
Copy link

ytilotti commented May 7, 2024

generating the images is slow

The generation can be only for one target and if not already generated. If the generated image is required, it's not a real problem.
But be careful about the context.

i hope we find the time eventually for a severe cleanup of the whole bundle with simple and clear names for the different options (getting the controller url versus generating an image and getting the url to the specific image)

Can be interesting.
In my case, it's for Mailjet tansactionnal. I need to be sure image was generate before send email.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants