Конфигурация диспетчера служб ZendFramework 2.0.0beta4 - разница между подразделами
РЕДАКТИРОВАТЬ: через несколько недель после того, как я опубликовал этот вопрос, Эван Коури написал отличное сообщение в блоге на тему ZF2 ServiceManager, где я нашел лучшие ответы на свои вопросы: http://blog.evan.pro/introduction-to-the-zend-framework-2-servicemanager
-
Я работаю над проектом, использующим ZendFramework 2.0.0beta4, и у меня возникают проблемы с использованием Zend\ServiceManager для обработки зависимостей. Вот текущая документация ZF2 ServiceManager
В нем перечислены 6 подразделов, которые можно использовать при регистрации классов в ServiceManager для использования в наших модулях: abstract_factories, псевдонимы, фабрики, invokables, services и shared. Если я просто хочу зарегистрировать класс модели, который я собираюсь использовать в своем контроллере для извлечения данных из базы данных, какой из них лучше? Я специально пытаюсь адаптировать пример из скелетного приложения ZF2, показанного ниже, к моему собственному приложению (DashboardTable - это модель), и в этом примере используется метод фабрики.
public function getServiceConfiguration()
{
return array(
'factories' => array(
'album-table' => function($sm) {
$dbAdapter = $sm->get('db-adapter');
$table = new DashboardTable($dbAdapter);
return $table;
},
'test-model' => Dashboard\Model\TestModel(),
),
);
}
Тем не менее, я не знаю, как "db-adapter" попадает в ServiceManager ($sm) в моем отдельном рабочем примере из SkeletonApplication - это связано с записью в автоматически загружаемом файле конфигурации global.php, которая имеет db 'запись, содержащая информацию БД. Поскольку я не знаю точно, как это происходит из файла конфигурации в ServiceManager, я создал простую запись ниже, чтобы свести проблему к ее базовым компонентам - "модель теста". Когда я закомментирую запись 'dashboard-table' и вызываю функцию из TestModel в моем контроллере, которая просто выводит некоторый текст. Ниже приведена конфигурация ServiceManager из моего Module.php
<?php
namespace Dashboard\Model;
class TestModel {
public function testMethod()
{
$testResult = "Hello";
return $testResult;
}
}
Который затем передается из моего контроллера в представление:
<?php
namespace Dashboard\Controller;
use Zend\Mvc\Controller\ActionController;
use Zend\View\Model\ViewModel;
use Dashboard\Model\AlbumTable;
use Dashboard\Model\TestModel;
use Dashboard\Model\Dashboard;
class DashboardController extends ActionController
{
public function indexAction()
{
return new ViewModel(array(
'users' => $this->getTestModel()->testMethod(),
));
}
public function getAlbumTable()
{
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('album-table');
}
return $this->albumTable;
}
public function getTestModel()
{
if (!$this->testModel) {
$sm = $this->getServiceLocator();
$this->testModel = $sm->get('test-model');
}
return $this->testModel;
}
}
Этот код дает мне полностью пустую страницу, без ошибок. Когда я комментирую конфигурацию ServiceManager из Module.php и просто отображаю новую ViewModel без передачи каких-либо аргументов в моем файле DashboardController.php, страница отображается нормально - загружаются layout.phtml и index.phtml.
Я полагаю, что я неправильно понимаю основную часть того, как использовать ServiceManager или возможный ZF2 в целом, и буду очень признателен за любую информацию, которую может дать любой. Это также мой первый вопрос о Stackru, поэтому я приветствую любые советы по форматированию моего вопроса. Благодарю.
3 ответа
Есть два хороших варианта получить фабрики от менеджеров по обслуживанию. Одним из них является создание фабричных классов, что чаще всего происходит в самом коде Zend Framework. Второй использует замыкания, как и вы.
Убедитесь, что вы не печатаете такие вещи, как:
'test-model' => Dashboard\Model\TestModel(),
Но настоящее закрытие, подобное вашему первому, является хорошим примером. Во-вторых, Service Manager всегда выдает исключение, когда вы пытаетесь получить сервис, который не может быть создан. Обратите внимание, что это исключение не включает сообщение почему: класс может не быть найден или исключение выдается во время создания экземпляра (например, потому что менеджер службы не может создать экземпляр службы, которую вы пытаетесь получить).
Последнее замечание: вам не нужно импортировать FQCN (полные имена классов) с use
заявления в месте, которое вы пытаетесь получить. Но вам нужно импортировать FQCN, когда вы пытаетесь создать экземпляр.
Так что это работает:
<?php
class MyClass
{
protected $sm;
public function setServiceManager($sm)
{
$this->sm = $sm;
}
public function doSomething()
{
$this->sm->get('some-special-key');
}
}
И это тоже:
<?php
use Foo\Bar\Baz;
$serviceConfig = array(
'factories' => array(
'some-special-key' => function($sm) {
return new Baz;
}
),
);
Но это не так (если вы пытаетесь получить Foo\Bar\Baz
):
<?php
$serviceConfig = array(
'factories' => array(
'some-special-key' => function($sm) {
return new Baz;
}
),
);
Вы можете проверить мой репозиторий SlmCmfKernel. В мой Module.php я включаю файл конфигурации сервиса, который находится в отдельном месте. В другой части кода я получаю услугу от менеджера.
Просто для ясности:
public function getServiceConfiguration()
{
return array(
'factories' => array(
'test-model' => function($sm){
return new Model\TestModel;
},
),
);
}
Может также быть написано как invokable:
public function getServiceConfiguration()
{
return array(
'invokables' => array(
'test-model' => 'Model\TestModel',
),
);
}
В этом случае вы можете рассмотреть возможность его определения в файле конфигурации вместо Module.php, поскольку вы сможете воспользоваться преимуществами кэширования конфигурации, поскольку это просто массив скаляров.
Я закончил тем, что нашел ответ на свой вопрос путем дополнительной отладки (ранее у меня не было ini_set('display_errors', '1'); set - глупый я).
Правильный синтаксис для добавления класса в ZF2 ServiceManager (внутри вашего Module.php) выглядит так:
public function getServiceConfiguration()
{
return array(
'factories' => array(
'album-table' => function($sm) {
$dbAdapter = $sm->get('db-adapter');
$table = new AlbumTable($dbAdapter);
return $table;
},
'test-model' => function($sm){
return new Model\TestModel;
},
),
);
}
И просто для полноты, чтобы вызвать метод из включаемого вами класса, вы можете использовать его в файле контроллера (в моем случае DashboardController.php), если вы расширяете класс ActionController:
class DashboardController extends ActionController
{
public function indexAction()
{
return new ViewModel(array(
'users' => $this->getTestModel()->testMethod(),
));
}
public function getTestModel()
{
if (!$this->testModel) {
$sm = $this->getServiceLocator();
$this->testModel = $sm->get('test-model');
}
return $this->testModel;
}
}
Где testMethod() - это метод из класса TestModel. Некоторые замечания по этому вопросу для тех, кто не знаком с Zend или пространствами имен - одна из моих проблем заключалась в том, что я использовал полную ссылку на имя класса (Dashboard\Model\TestModel), когда для пространства имен в верхней части файла было установлено значение Dashboard, поэтому первая Dashboard была ненужной и заставила PHP искать Dashboard\Dashboard\Model\TestModel. Кроме того, на момент написания этого примера образцы ZF2 отсутствуют, я рекомендую поискать примеры таких вещей, как ZfcUser от EvanDotPro.
Однако мое первоначальное замешательство по поводу различных подключей для добавления классов в ServiceManager все еще сохраняется, поэтому, если у вас есть какое-либо представление об этом, я буду продолжать следить за этим вопросом и отмечу ваш ответ как "ответ", если вы решите этот бит, благодарю вас:).