在服务中使用运行时参数的Symfony

时间:2018-07-02 11:11:22

标签: php symfony dependency-injection

我需要初始化一个将注入某些服务的对象。他的一些参数可以在运行时从请求参数中获取。 我应该如何处理这样的动态对象?

我发现的第一种方法是使设置器和传递参数引发使用该对象的服务。但是我觉得这很臭。

第二种方法是将我的对象标记为“综合服务”。因此,我必须在构造函数中准备对象并将其设置为服务容器。

我不确定这是最好的方法。有人可以建议我在这种情况下采取正确的做法吗?

第一种方法的伪代码示例:

class Storage {
    private $path;
    private $project;

    public function __construct($path) {
        $this->path = $path;
    }

    public function setProject($project): void {
        $this->project = $project;
    }

    public function showFullPath() {
        echo "Full path: {$this->path}/{$this->project}";
    }
}

class Service {
    private $storage;

    public function __construct(Storage $storage) {
        $this->storage = $storage;
    }

    public function doSomething($project) {
        $this->storage->setProject($project);
        $this->storage->showFullPath();
    }
}


// in controller
$service = $container->get('Service');
$service->doSomething($project);

第二种方法的伪代码示例:

class Storage {
    private $path;
    private $project;

    public function __construct($path, $project) {
        $this->path = $path;
        $this->project = $project;
    }

    public function showFullPath() {
        echo "Full path: {$this->path}/{$this->project}";
    }
}

class Service {
    private $storage;

    public function __construct(Storage $storage) {
        $this->storage = $storage;
    }

    public function doSomething() {
        $this->storage->showFullPath();
    }
}


// in controller
$storage = new Storage($path, $project);
$container->set('Storage', $storage);

$service = $container->get('Service');
$service->doSomething();

2 个答案:

答案 0 :(得分:0)

如果从请求中检索到您需要的参数,为什么不将请求堆栈注入Storage,然后在showFullPath上从请求的堆栈主请求中获取所需的参数?

use Symfony\Component\HttpFoundation\RequestStack;

class Storage {
  private $path;
  private $requestStack;

  public function __construct($path, RequestStack $requestStack) {
      $this->path = $path;
      $this->requestStack = $requestStack;
  }

  public function showFullPath() {
      $project = $this->requestStack->getMasterRequest()->getYourParametersHereFromRequest();
      echo "Full path: {$this->path}/{$project";
  }
}

答案 1 :(得分:0)

我同意gvf的观点,在这种情况下,使用RequestStack方法是一个很好的解决方案。但是,如果您坚持使用控制器中的请求对象,则可以引入工厂服务来创建存储对象:

class StorageFactory
{
    public function createStorage(Request $request) : Storage
    {
        // ... create $storage from $request
        return $storage;
    }
}


class Service
{
    public function doSomething(Storage $storage)
    {
        // ...
    }
}

// in your controller
$storage = $container->get("storage_factory")->createStorage($request);
$container->get('Service')->doSomething($storage);

如您所见,您将必须将$storage对象作为参数传递给doSomething方法。无法在构造函数中进行设置,因为您明确希望在设置服务后创建$storage对象。

顺便说一句:setter注入很糟糕,因为它允许服务处于不一致状态。尽可能避免使用它(以及一般的塞特犬)。