Внедрение зависимостей в базовые и производные классы

У меня есть абстрактный базовый класс контроллера, и все контроллеры действий являются производными от него.

Базовый класс Controller при построении инициализирует объект View. Этот объект View используется всеми контроллерами действий. Каждый контроллер действий имеет разные зависимости (это решается с помощью контейнера DI).

Проблема в том, что базовому классу Controller также нужны некоторые зависимости (или параметры), например, путь к папке просмотра. И вопрос - куда и как передать параметры базовому классу Controller?

$dic = new Dic();

// Register core objects: request, response, config, db, ...

class View
{
    // Getters and setters
    // Render method
}

abstract class Controller
{
    private $view;

    public function __construct()
    {
        $this->view = new View;

        // FIXME: How / from where to get view path?
        // $this->view->setPath();
    }

    public function getView()
    {
        return $this->view;
    }
}

class Foo_Controller extends Controller
{
    private $db;

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

    public function barAction()
    {
        $this->getView()->some_var = 'test';
    }
}

require_once 'controllers/Foo_Controller.php';

// Creates object with dependencies which are required in __construct()
$ctrl = $dic->create('Foo_Controller');

$ctrl->barAction();

person Hemaulo    schedule 17.02.2012    source источник
comment
приватный просмотр; почему $view приватный? Когда вы знаете, какой путь просмотра для загрузки? Внутри контроллера действий? Тогда это можно легко сделать.   -  person busypeoples    schedule 17.02.2012


Ответы (1)


Это просто базовый пример. Почему $view приватный? Есть веская причина?

class View {
  protected $path;
  protected $data = array();

  function setPath($path = 'standard path') {
    $this->path = $path;
  }

  function __set($key, $value) {
    $this->data[$key] = $value;
  }

  function __get($key) {
    if(array_key_exists($key, $this->data)) {
      return $this->data[$key];
    }
  }
}

abstract class Controller {
    private $view;

    public function __construct($path)
    {
       $this->view = new View;

       $this->view->setPath($path);
    }

    public function getView()
    {
        return $this->view;
    }
}

class Foo_Controller extends Controller {
    private $db;


    public function __construct(Db $db, $path)
    {
        // call the parent constructor.
        parent::__construct($path);
        $this->db = $db;
    }

    public function barAction()
    {
        $this->getView()->some_var = 'test';
    }

    public function getAction() {
      return $this->getView()->some_var;
    }
}

class DB {

}

$con = new DB;
$ctrl = new Foo_Controller($con, 'main');

$ctrl->barAction();
print $ctrl->getAction();
person busypeoples    schedule 17.02.2012
comment
Спасибо за ваш быстрый ответ! Представление является частным, поэтому его нельзя переопределить извне, доступ к нему возможен только с помощью метода getView(). Извините, я забыл упомянуть, что существует только один путь просмотра (например, «представления/»), определенный как константа в файле начальной загрузки. Кажется правильным передать путь просмотра из конструктора контроллера действий. Но если путь не меняется, есть ли какое-то другое решение (в пользу DI), поэтому каждому контроллеру действий не нужно вызывать родительский конструктор и снова и снова передавать один и тот же путь представления? - person Hemaulo; 17.02.2012
comment
Лучший подход — определить путь по умолчанию внутри родительского абстрактного контроллера. приватный $view ->путь = какой-то путь; - person busypeoples; 17.02.2012
comment
@Hemaulo Вы переопределяете конструктор внутри контроллера действий, имейте это в виду. Без вызова parent::__controller, как будет вызываться представление? - person busypeoples; 17.02.2012
comment
Класс базового контроллера является частью фреймворка, а путь просмотра определяется приложением. Ваше решение - самый простой способ, но тогда путь просмотра будет жестко запрограммирован и относителен. Предпочтителен абсолютный путь, но каждое приложение находится в отдельной папке. - person Hemaulo; 17.02.2012
comment
Родительский конструктор нужно вызывать только в том случае, если дочерний класс определяет собственный метод __construct(). Могут быть контроллеры без зависимостей и, следовательно, без конструктора, и в этом случае parent::__construct() будет вызываться автоматически. - person Hemaulo; 17.02.2012
comment
Да, я понимаю. Но в вашем примере кода вам придется вызывать родительский конструктор. Как в этом примере будет установлено представление? - person busypeoples; 17.02.2012