Symfony2服务

时间:2016-11-05 17:51:13

标签: php symfony service

我在DB中有2个表(questionanswer)。一个问题有很多答案。

我得到一些Answers并依赖于question.type我准备结果数组。

在没有任何框架的app中,我有Factory类返回特定对象(SingleChoiceQuestionOpenQuestionMultipleChoiceQuestion)取决于来自DB的question.type。所有Questions都扩展了已声明Question方法abstract的抽象类getResults。所有类型都有自己的业务逻辑来准备结果。

所以在这种情况下,当我按工厂创建对象时,我正在使用方法getResults,一切运行良好。

我想在Symfony中创建它并阅读文档。在我看来,我应该为我的所有Question类型创建服务。

我创建了AggregatedResultsManager方法generate,它返回结果数组。取决于question.type它从特定getResults调用service方法。

我想补充一点,我无法改变数据库结构。

我的问题:

  1. 我是否正在创建和使用services?如果我做错了,请帮助我理解并告诉我正确的方法。
  2. 我将提供多项服务,例如AggregatedResultsManager和约18种问题类型。
  3. 在每项服务中,我需要创建switch有18个选项,如何防止这种情况?

    switch ($this->question->getType()) {
        case Question::SINGLE:
            $results = $this->container->get('app.single_choice_question')->getResults($answers);
            break;
        // other types
    }
    

    我有一些想法来创建包含类型和服务名称的数组:

    $services = [
        Question::SINGLE => 'app.single_choice_question',
        Question::MULTIPLE => 'app.multiple_choice_question',
        Question::OPEN => 'app.open_question',
    ];
    

    然后在每个服务中使用它:

    $results = $this->container->get($services[$this->question->getType()])->getResults($answers);
    

    我认为这是不使用18种选择的开关的最佳方式。但我需要在数组中对服务名称进行硬编码。

    我的代码:

    services.yml

    app.question:
        class: AppBundle\Questions\Question
        abstract: true
        arguments: ['@doctrine.orm.entity_manager']
    
    app.single_choice_question:
        class: AppBundle\Questions\SingleChoice
        parent: app.question
    
    app.agreggated_results_manager:
        class:  AppBundle\Results\AggregatedResultsManager
        arguments: ['@doctrine.orm.entity_manager', '@service_container']
    

    抽象问题

    abstract class Question
    {
        /**
         * @var EntityManager
         */
        protected $em;
    
        public function __construct(EntityManager $em)
        {
            $this->em = $em;
        }
    
        abstract public function getResults($answers);
    }
    

    SingleChoice

    class SingleChoice extends Question
    {
        public function getResults($answers)
        {
            $results = [];
    
            // business logic
    
            return $results;
        }
    }
    

    结果

    class AggregatedResultsManager
    {
        /**
         * @var EntityManager
         */
        private $em;
    
        /**
         * @var Question
         */
        private $question;
    
        /**
         * @var ContainerInterface
         */
        private $container;
    
        public function __construct(EntityManager $em, ContainerInterface     $container)
        {
            $this->em = $em;
            $this->container = $container;
        }
    
        public function generate()
        {
            if (!$this->question) {
                throw new \LogicException('Question is not set');
            }
    
            $answers = $this->em
                ->getRepository('AppBundle:Answer')
                ->findBy(['question' => $this->question]);
    
            $results = [];
    
            if (empty($answers)) {
                return $results;
            }
    
            switch ($this->question->getType()) {
                case Question::SINGLE:
                    $results = $this->container->get('app.single_choice_question')->getResults($answers);
                    break;
                // other types
            }
    
            return $results;
        }
    
    
        public function setQuestion(Question $question)
        {
            $this->question = $question;
        }
    }
    

    控制器

    public function questionIdsAction(Question $question)
    {
        $resultsManager = $this->get('app.agreggated_results_manager');
        $resultsManager->setQuestion($question);
        $results = $resultsManager->generate();
    
        return new JsonResponse($results);
    }
    

1 个答案:

答案 0 :(得分:1)

我认为你说你有18个QuestionTypes都扩展了一个AbstractQuestion,需要实体经理去做它的工作?而不是制作18个服务然后使用容器我建议制作一个问题工厂:

class QuestionFactory
    public function __construct($entityManager)
        $this->entityManager = $entityManager;
    public function create($questionType)
        switch($questionType) {
            case Question::SINGLE: return new SingleQuestion($this->entityManager);

然后,您将工厂注入结果管理器。

这种方法避免了创建一堆服务和需要传递容器的需要。你还有一个switch语句,但没关系。

可能出现的唯一问题是某些QuestionTypes是否需要其他依赖项。在这种情况下,您可能会回到使用服务。