Как заставить serviceManager работать на классе zf2

У меня есть некоторые сервисы, определенные в моем module.php, который работает как задумано, объявленный как:

public function getServiceConfig()
{
return array(
'factories' => array(
'Marketplace\V1\Rest\Service\ServiceCollection' =>  function($sm) {
$tableGateway = $sm->get('ServiceCollectionGateway');
$table = new ServiceCollection($tableGateway);
return $table;
},
'ServiceCollectionGateway' => function ($sm) {
$dbAdapter = $sm->get('PdoAdapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new ServiceEntity());
return new TableGateway('service', $dbAdapter, null, $resultSetPrototype);
},
'Marketplace\V1\Rest\User\UserCollection' =>  function($sm) {
$tableGateway = $sm->get('UserCollectionGateway');
$table = new UserCollection($tableGateway);
return $table;
},
'UserCollectionGateway' => function ($sm) {
$dbAdapter = $sm->get('PdoAdapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new UserEntity());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
),
);
}

Я использую их для сопоставления моих таблиц БД с объектом. Из моих основных классов моего проекта я могу получить к ним доступ без каких-либо проблем. Посмотрите на мое дерево файлов проекта:

введите описание изображения здесь

Например, userResource.php расширяет abstractResource, и эта функция работает:

public function fetch($id)
{
$result = $this->getUserCollection()->findOne(['id'=>$id]);
return $result;
}

Внутри ResourceAbstract у меня есть:

<?php

namespace Marketplace\V1\Abstracts;

use ZF\Rest\AbstractResourceListener;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class ResourceAbstract extends AbstractResourceListener implements ServiceLocatorAwareInterface {

protected $serviceLocator;public function getServiceCollection() {
$sm = $this->getServiceLocator();
return $sm->get('Marketplace\V1\Rest\Service\ServiceCollection');
}

public function getUserCollection() {
$sm = $this->getServiceLocator();
return $sm->get('Marketplace\V1\Rest\User\UserCollection');
}

public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}

public function getServiceLocator() {
return $this->serviceLocator;
}

}

Там, как предложено в документации Zf2, мне нужно реализовать ServiceLocatorAwareInterface, чтобы использовать serviceManager. Все идет нормально. Тогда я решил добавить новый класс, вызвать Auth.

Этот класс не очень отличается от abstractResource, он получает вызов в loginController следующим образом:

<?php
namespace Marketplace\V1\Rpc\Login;

use Zend\Mvc\Controller\AbstractActionController;
use Marketplace\V1\Functions\Auth;

class LoginController extends AbstractActionController
{
public function loginAction()
{
$auth = new Auth();
$data = $this->params()->fromPost();
var_dump($auth->checkPassword($data['email'], $data['password']));

die;
}}

Это Auth:

<?php

namespace Marketplace\V1\Functions;use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Auth implements ServiceLocatorAwareInterface {

protected $serviceLocator;

public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}

public function getServiceLocator() {
return $this->serviceLocator;
}

public function checkPassword($email, $rawPassword) {

$user = $this->getServiceLocator()->get('Marketplace\V1\Rest\User\UserCollection')->findByEmail($email);
if($user)
return false;

$result = $this->genPassword($rawPassword, $user->salt);

if($result['password'] === $user->password)
return true;
else
return false;

}

public function genPassword($rawPassword, $salt = null) {
if(!$salt)
$salt = mcrypt_create_iv(22, MCRYPT_DEV_URANDOM);
$options = [
'cost' => 11,
'salt' => $salt,
];
return ['password' => password_hash($rawPassword, PASSWORD_BCRYPT, $options), 'salt' => bin2hex($salt)];
}

}

Как вы можете видеть, он следует по тому же пути, что и abtractResource, НО, в этом случае, когда я выполняю loginController, я получаю ошибку:

Fatal error</b>:  Call to a member function get() on null in C:\WT-NMP\WWW\MarketPlaceApi\module\Marketplace\src\Marketplace\V1\Functions\Auth.php on line 25

И это относится к этой строке: $user = $this->getServiceLocator()->get('Marketplace\V1\Rest\User\UserCollection')->findByEmail($email);

Это означает, что getServiceLocator пуст. Почему я не могу заставить serviceLocator работать с классом Auth, но могу это сделать в abstractResource?

0

Решение

Это потому что ServiceLocator впрыскивается через механизм, называемый «сеттерная инъекция». Для того, чтобы это произошло, что-то (например, ServiceManager) необходимо вызвать сеттер для класса, в этом случае setServiceLocator, Когда вы непосредственно создаете экземпляр Auth это не тот случай. Вам нужно добавить свой класс в локатор службы, например, в качестве вызываемой службы.

Например.:

public function getServiceConfig()
{
return array(
'invokables' => array(
'Auth' => '\Marketplace\V1\Functions\Auth',
),
);
}

или, что более удобно, поскольку он не использует анонимную функцию для фабрики, поместите ее в конфигурационный файл ваших модулей `modules / Marketplace / config / module.config.php ‘:

// ...
'service_manager' => array(
'invokables' => array(
'Auth' => '\Marketplace\V1\Functions\Auth',
),
),

и вы можете получить Auth из сервисного локатора в вашем контроллере:

$auth = $this->getServiceLocator()->get('Auth');

вместо:

$auth = new Auth;

Таким образом, сервисный локатор построит Auth для вас, проверьте, какие интерфейсы он реализует и когда он узнает, что он реализует ServiceLocatorAwareInterface тогда он запустит сеттер, передав в него экземпляр самого себя. Интересный факт: сам контроллер получает инъекцию экземпляра локатора службы таким же образом (это предок этот класс реализовать тот же интерфейс). Еще один забавный факт: это поведение может измениться в будущем, как обсуждается здесь.

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector