5

I've followed the Symfony 5.2 tutorial to add a FileUploader as a service (https://symfony.com/doc/current/controller/upload_file.html).

So this is my service.yaml

parameters:
  targetDirectory: '%kernel.project_dir%/public/uploads/'
  previews_video: '%kernel.project_dir%/public/uploads/previews'
  brochures_directory: '%kernel.project_dir%/public/uploads/brochures'
services:
  App\Service\FileUploader:
      arguments:
          $targetDirectory: '%previews_video%'

And this is my FileUploader.php

<?php


namespace App\Service;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\String\Slugger\SluggerInterface;

class FileUploader
{
    private $targetDirectory;
    private $slugger;

    public function __construct($targetDirectory, SluggerInterface $slugger)
    {
        $this->targetDirectory = $targetDirectory;
        $this->slugger = $slugger;
    }

    public function upload(UploadedFile $file)
    {
        $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $safeFilename = $this->slugger->slug($originalFilename);
        $fileName = $safeFilename.'-'.uniqid().'.'.$file->guessExtension();

        try {
            $file->move($this->getTargetDirectory(), $fileName);
        } catch (FileException $e) {
            // ... handle exception if something happens during file upload
        }

        return $fileName;
    }

    public function getTargetDirectory()
    {
        return $this->targetDirectory;
    }
}

But I'm having this common error :

Cannot resolve argument $fileUploader of "App\Controller\VideoController::edit()": Cannot autowire service "App\Service\FileUploader": argument "$targetDirectory" of method "__construct()" has no type-hint, you should configure its value explicitly.

Called by this controller :

 /**
 * @Route("/{id}/edit", name="video_edit", methods={"GET","POST"})
 * @param Request $request
 * @param Video $video
 * @param FileUploader $fileUploader
 * @return Response
 */
public function edit(Request $request, Video $video, FileUploader $fileUploader): Response
{...}

How do I fix this ? I trying by remove the string type, adding the string type, removing the $ from the targetDirectory parameters in services.yaml... Struggling with that for hours now...

lucrece
  • 174
  • 11
  • Are your services configured to be autowired using `autowire: true`? – Jeroen van der Laan Mar 14 '21 at 21:49
  • service.yaml or services.yaml? Not doing any sort of bundle nonsense are you? Does 'bin/console debug:container FileUploader' offer any clues? And don't forget the magical clearing of the cache. – Cerad Mar 14 '21 at 21:55
  • **services.yaml**, and already cleared the cache – lucrece Mar 15 '21 at 10:05
  • You have something strange going on here. I made a simple test case with your service. Without changing anything in config/services.yaml I got the same error as you as expected. I copied/pasted in your configuration and everything worked. I thought maybe the fact that you had a parameter named targetDirectory might be the issue but it is not. All I can suggest at this point is to make a new project, copy in your service and try injecting it. Maybe double check that the Service directory has not been excluded from autowire. – Cerad Mar 15 '21 at 12:13

5 Answers5

3

Take a look at my working services.yaml. I've changed the namespace

App\Service

to

App\Services

And I also added the service declaration at the end of the file.

Looks like the order of the lines in services matter. First, I've added the declaration at the top of the services part, but the autowiring is declared after, guess the error was here...

# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    previews_directory: '%kernel.project_dir%/public/uploads/previews'
services:
  #i've added my service here at first... 
    app.menu_builder:
        class: App\Menu\MenuBuilder
        arguments: ["@knp_menu.factory"]
        tags:
            - { name: knp_menu.menu_builder, method: createMainMenu, alias: main }
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'
            - '../src/Tests/'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller/'
        tags: ['controller.service_arguments']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones

    App\Services\FileUploader:
        arguments:
            $targetDirectory: '%previews_directory%'
lucrece
  • 174
  • 11
  • I had a tough time figuring out what I am doing wrong. Anyway, I have just found that if you use `#[AsController]` attribute on top of the controller w/o extending the AbstractController does work too. And also it requires to have `symfony/http-kernel` package installed. – ssi-anik Sep 18 '21 at 02:03
1

Add a type-hint string for $targetDirectory in the contructor

public function __construct(string $targetDirectory, SluggerInterface $slugger)
{
    $this->targetDirectory = $targetDirectory;
    $this->slugger = $slugger;
}
Artem
  • 1,426
  • 12
  • 17
0

You should have autowiring configuration added to your services file:

parameters:
  targetDirectory: '%kernel.project_dir%/public/uploads/'
  previews_video: '%kernel.project_dir%/public/uploads/previews'
  brochures_directory: '%kernel.project_dir%/public/uploads/brochures'
services:
  # To add:
  _defaults:
      autowire: true
      autoconfigure: true
  # You service
  App\Service\FileUploader:
      arguments:
          $targetDirectory: '%previews_video%'
MustaphaC
  • 11
  • 2
0

I had the same issue. It was related to the indentation of that specific service. I wasn't getting any indentation error but also the auto wiring wasn't working. What i did was to add 4 spaces as indentation

    App\Service\FileUploader:
        arguments:
            $targetDirectory: '%TEAM_LOGO_DIRECTORY%'
cosmo
  • 1
0

Yes I got the problem too and I managed to solve it by replacing indentation by spaces in the services.yaml file, I added all of these properties at the same root and then I did that and it works for me:

services:
    App\Services\FileUploader: #(added 4 spaces, NOT 1 tab)
        arguments: #(added 8 spaces, NOT 2 tabs)
            $targetDirectory: '%cats_directory%' #(added 12 spaces, NOT 3 tabs)

If you struggle you (and other people who got this problem) can try this solution. I don't guarantee it will work 100%.

pimoux
  • 1
  • 1