Symfony 5 сервис не загружается - PullRequest
0 голосов
/ 12 апреля 2020

Я получил класс использования для загрузки файла как службы, как symfony документация. https://symfony.com/doc/current/controller/upload_file.html#creating -an-uploader-service

Я использую symfony 5.

Когда я объявляю службу в main config / services.yaml, эта работа.

Но у меня есть пакет для управления файлами, и я хочу поместить объявление службы в этот пакет: App / AD / ExplorerBundle / Resources / config / services.yaml.

Когда я это делаю, это больше не работает.

У меня ошибка

Невозможно разрешить аргумент $ fileUploader для "App \ AD \ ExplorerBundle \ Controller \" FileController :: addAction () ": Невозможно автоматически подключить службу" App \ AD \ ExplorerBundle \ Service \ FileUploader ": аргумент" $ targetDirectory "метода" __construct () "является подсказкой типа" строка ", вы должны явно указать его значение.

Я не понимаю почему, потому что _defaults autoconfigure и autowire = true

Я проверяю кеш: очистить, перезагрузить сервер, но ничего не работает.

Любая помощь будет цениться

Редактировать: расширение моего пакета: в AD \ ExplorerBundle \ DependencyInjection

<?php

namespace App\AD\ExplorerBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * This is the class that loads and manages your bundle configuration.
 *
 * @link http://symfony.com/doc/current/cookbook/bundles/extension.html
 */
class ADExplorerExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
    }
}

мой сервис пакета: в AD \ ExplorerBundle \ Service

<?php
namespace App\AD\ExplorerBundle\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(string $targetDirectory, SluggerInterface $slugger)
    {
        $this->targetDirectory = $targetDirectory;
        $this->slugger = $slugger;
    }

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

        $result = array(
            'filename' => $fileName,
            'originalName' => $originalFilename,
            'extension' => $file->guessExtension()
                );

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

        return $result;
    }

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

мой config / services.yaml

parameters:
    locale: 'fr'
    doctrine_behaviors_translatable_fetch_mode: "LAZY"
    doctrine_behaviors_translation_fetch_mode: "LAZY"



imports:
    - { resource: '@ADCoreBundle/Resources/config/services.yml' }
    - { resource: './parameters.yaml' }

services:
    # 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.

    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'


    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']

мой сервис Bundle: в AD \ ExplorerBundle \ Resources \ config \ service.yaml

parameters:
    brochures_directory: '%kernel.project_dir%/public/uploads'

services: 
    ad_file_uploader:         
        class: App\AD\ExplorerBundle\Service\FileUploader
        arguments:
            $targetDirectory: '%brochures_directory%'

Я читаю документацию: https://symfony.com/doc/current/bundles/extension.html

https://symfony.com/doc/current/service_container.html#manually -провода-аргументы

https://symfony.com/doc/current/service_container/autowiring.html

Я действительно не понимаю этого:

Publi c и многоразовые пакеты¶

Publi c связки следует явно настроить свои сервисы и не полагаться на автопроводку. Автопроводка зависит от сервисов, доступных в контейнере, и пакеты не контролируют сервисный контейнер приложений, в которые они включены. Вы можете использовать автопроводку при создании пакетов многократного использования в вашей компании, так как у вас есть полный контроль над всем кодом.

Я думаю, что все в порядке, потому что это мой пакет и мое приложение, поэтому у меня полный контроль над кодом.

Итак, я тестирую много вещей, но ничего не получается.

Если у кого есть идея Спасибо

1 Ответ

1 голос
/ 14 апреля 2020

Symfony рекомендует использовать определения сервисов вручную в пакетах, главным образом, чтобы избежать лишних затрат на постоянное сканирование пакета при каждой перестройке кэша. Но я подумал, что было бы интересно посмотреть, что на самом деле влечет за собой создание потенциально многоразового пакета с autowire / autoconfigure. Пытался следовать рекомендациям по комплектам столько, сколько мог.

Для справки я зарегистрировал пример полного комплекта работ .

В конечном итоге, пакеты должны заканчиваться в своем собственном хранилище. Однако может быть проще разработать пакет, заключив его в приложение. Это подход, который я использовал. Но важно не пытаться смешивать исходный код вашего приложения с исходным кодом пакета. Это не только сложно, но и затруднит копирование вашего пакета в его собственный репозиторий.

Итак, мы начнем с такой структуры каталогов:

project # Symfony application project
    src: # Application source code
    explorer-bundle # AD Explorer Bundle source code
        ADExplorerBundle.php

Правильно получить ваше пространство имен тоже важно. Префикс действительно должен быть уникальным идентификатором поставщика, чтобы избежать возможных конфликтов имен. В этом случае мы используем AD. И, конечно же, поскольку AD может иметь несколько пакетов, мы дополнительно подразделяем с помощью идентификатора пакета c.

namespace AD\ExplorerBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class ADExplorerBundle extends Bundle
{

}

Чтобы автозагрузка работала, мы настраиваем composer. json файл. Как только пакет будет преобразован в истинный пакет composer, эта строка больше не будет нужна. И, конечно, вы должны добавить класс bundle в project / config / bundles. php

# composer.json
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "AD\\ExplorerBundle\\": "explorer-bundle/"
        }
    },
# run composer "dump-autoload" after making this change

Так что теперь нам нужно расширение для загрузки services.yaml пакета. Это просто стандартная загрузка, поэтому нет необходимости показывать код здесь. Вот как выглядит файл services.yaml:

# explorer-bundle/Resources/config/services.yaml
parameters:
    # Cheating here, this would normally be part of the bundle configuration
    ad_explorer_target_directory: 'some_directory'

services:
    _defaults:
        autowire: true
        autoconfigure: true
        bind:
            $targetDirectory: '%ad_explorer_target_directory%'

    AD\ExplorerBundle\:
        resource: '../../*'
        exclude: '../../{DependencyInjection,Entity,Migrations,Tests,ADExplorerBundle.php}'

    AD\ExplorerBundle\Controller\:
        resource: '../../Controller'
        tags: ['controller.service_arguments']

Для простоты я просто сделал целевой каталог параметром. Вы, вероятно, захотите создать реальную конфигурацию пакета и дать приложению возможность установить ее. Но это выходит за рамки этого ответа.

Для тестирования я решил создать команду. Я считаю это проще, чем пытаться обновить sh браузер.

// Easier to debug an injected service using a command than a controller
class ExplorerAddCommand extends Command
{
    private $fileUploader;

    protected static $defaultName = 'ad:explorer:add';

    public function __construct(FileUploader $fileUploader)
    {
        parent::__construct();
        $this->fileUploader = $fileUploader;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        echo "Explorer Add " . $this->fileUploader->targetDirectory . "\n";
        return 0;
    }
}

И это все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...