Как использовать одни и те же модели в разных модулях в Zend Framework?

Я работаю над внедрением Zend Framework в существующий проект, в котором есть зона публичного маркетинга, зона частных участников, сайт администрирования и сайт управления маркетинговой кампанией. В настоящее время они плохо организованы: сценарии контроллера для области маркетинга и области для участников находятся в корне сайта, а затем отдельная папка для администратора и еще одна папка для сайта маркетинговой кампании.

При реализации Zend Framework я хотел бы создать возможность разделить контроллеры и представления на модули (один для области участников, один для области публичного маркетинга, один для сайта администрирования и один для сайта администрирования маркетинговой кампании) но мне нужно указать каждый модуль на одну и ту же модель, поскольку все три компонента работают с одной и той же базой данных и с одними и теми же бизнес-объектами.

Однако мне не удалось найти в документации никакой информации о том, как это сделать. Может ли кто-нибудь помочь со ссылкой на то, как это сделать, или с некоторыми простыми инструкциями о том, как это сделать?


person Noah Goodrich    schedule 03.11.2008    source источник


Ответы (4)


Что я делаю, так это храню общие классы в «библиотечном» каталоге вне иерархии модулей. Затем установите мой INCLUDE_PATH на использование каталога "models" соответствующего модуля плюс общий каталог "library".

docroot/
    index.php
application/
    library/    <-- common classes go here
    default/
        controllers/
        models/
        views/
    members/
        controllers/
        models/
        views/
    admin/
        controllers/
        models/
        views/
. . .

В моем сценарии начальной загрузки я бы добавил "application/library/" к INCLUDE_PATH. Затем в функции init() каждого контроллера я бы добавил каталог этого модуля «models/» в INCLUDE_PATH.

изменить: такие функции, как setControllerDirectory() и setModuleDirectory(), не добавляют соответствующие каталоги моделей в INCLUDE_PATH. В любом случае это придется делать самому. Вот один из примеров того, как это сделать:

$app = APPLICATION_HOME; // you should define this in your bootstrap
$d = DIRECTORY_SEPARATOR;
$module = $this->_request->getModuleName(); // available after routing
set_include_path(
  join(PATH_SEPARATOR,
    array(
      "$app{$d}library",
      "$app{$d}$module{$d}models",
      get_include_path()
    )
  )
);

Вы можете добавить «library» к своему пути в начальной загрузке, но вы не можете добавить каталог «models» для правильного модуля в начальной загрузке, потому что модуль зависит от маршрутизации. Некоторые люди делают это в init() методе своих контроллеров, а некоторые пишут плагин для хука preDispatch ActionController, чтобы установить INCLUDE_PATH.

person Bill Karwin    schedule 03.11.2008
comment
Есть ли причина, по которой вы не используете addControllerDirectory () вместо добавления значения в INCLUDE_PATH? - person Noah Goodrich; 03.11.2008
comment
Насколько мне известно, addControllerDirectory () не добавляет соответствующий каталог моделей в ваш путь включения. См. Примеры в моей редакции выше. - person Bill Karwin; 03.11.2008

Этого также можно достичь с помощью соглашения об именах, которое следует за Zend_Loader. Храните файлы модели в папке моделей в папке их модуля. Назовите их Module_Models_ModelName и сохраните их в файле с именем ModelName.php в папке моделей для этого модуля. Убедитесь, что папка приложения находится в вашем пути включения, и, предполагая, что вы используете Zend_Loader для автоматической загрузки, вы можете просто ссылаться на модели по имени их класса.

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

person D-Rock    schedule 16.11.2008

Я только что создал этот специальный помощник для решения описываемой вами проблемы:

<?php

class My_Controller_Action_Helper_GetModel extends Zend_Controller_Action_Helper_Abstract
{
  /**
   * @var Zend_Loader_PluginLoader
   */
  protected $_loader;

  /**
   * Initialize plugin loader for models
   * 
   * @return void
   */
  public function __construct()
  {
    // Get all models across all modules
    $front = Zend_Controller_Front::getInstance();
    $curModule = $front->getRequest()->getModuleName();

    // Get all module names, move default and current module to
    //  back of the list so their models get precedence
    $modules = array_diff(
      array_keys($front->getDispatcher()->getControllerDirectory()),
      array('default', $curModule)
    );
    $modules[] = 'default';
    if ($curModule != 'default') {
      $modules[] = $curModule;
    }

    // Generate namespaces and paths for plugin loader
    $pluginPaths = array();
    foreach($modules as $module) {
      $pluginPaths[ucwords($module)] = $front->getModuleDirectory($module) . '/models';
    }

    // Load paths
    $this->_loader = new Zend_Loader_PluginLoader($pluginPaths);
  }

  /**
   * Load a model class and return an object instance
   * 
   * @param  string $model 
   * @return object
   */
  public function getModel($model)
  {
    $class = $this->_loader->load($model);
    return new $class;
  }

  /**
   * Proxy to getModel()
   * 
   * @param  string $model 
   * @return object
   */
  public function direct($model)
  {
    return $this->getModel($model);
  }
}

Итак, в вашем Bootstrap.php:

Zend_Controller_Action_HelperBroker::addPrefix('My_Controller_Action_Helper');

И в любом из ваших контроллеров:

<?php

class IndexController extends Zend_Controller_Action 
{
  public function indexAction() 
  {
    $model = $this->_helper->getModel('SomeModel');
  }
}

И это позволит вам получить доступ к моделям в любом контроллере во всех модулях.

person Jake McGraw    schedule 02.06.2009

У меня такая же проблема. Ответ Билла мне не подходит, потому что я склонен разделять свои модули не на «кто их видит», а на «что они делают». Например, «модуль форума» может управляться как администратором, так и публикой. Я пытаюсь иметь модули внешнего интерфейса, такие как admin, members, public, но затем они используют другие модули, такие как «forum / validatepost», «forum / show users personal info». Если бы кто-нибудь мог пролить свет на то, как они защищают серверный модуль от общественности, то это было бы удобно. Я предполагаю, что ACL может быть ключом, но меня все еще беспокоит то, что доступ контролируется объектами, а не файловой системой / .htaccess и т. Д.

Чтобы ответить на вопрос PHPoet: (i) Пути к каталогам контроллеров модулей могут быть указаны с помощью вызовов фронт-контроллера: например, см .: «12.11.2. Указание каталогов контроллеров модулей» (Документы Zend Framework)

(ii) Пути к представлениям могут быть установлены с помощью ViewRenderer (Controller Action Helper), например. см .: 'Пример 12.12. Выбор другого сценария просмотра »(Документы Zend Framework)

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

(Я не изучал, как работает автозагрузчик, но было бы разумно иметь некоторую систему сопоставления для решения такого рода проблем.)

person Community    schedule 20.05.2009