Symfony service FileUploader not autowiring

Viewed 1211

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...

4 Answers

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%'

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%'

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

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

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%'
Related