Конфигурация диспетчера служб 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 все еще сохраняется, поэтому, если у вас есть какое-либо представление об этом, я буду продолжать следить за этим вопросом и отмечу ваш ответ как "ответ", если вы решите этот бит, благодарю вас:).

Другие вопросы по тегам