我为我的模块编写了一个自定义服务。此服务提供公共静态函数,该函数应验证给定的标记。
现在我想实现另一个公共静态函数,它检查是否存在Doctrine-Entity。对于这种情况,我需要服务中的对象管理器或服务定位器。
class ApiService
{
const KEY_LENGTH = 10;
const USE_NUMBERS = true;
const USE_CHARS = true;
public static function isValid($apiKey) {
$isValid = false;
# more code tbd
$isValid = self::exists($apiKey);
return $isValid;
}
public static function exists($apiKey) {
# Insert Object-Manager here
$validator = new \DoctrineModule\Validator\ObjectExists(array(
'object_repository' => $objectManager->getRepository('Application\Entity\User'),
'fields' => array('email')
));
}
}
将我的函数实现为public static并将它们称为静态方法是“最佳实践”吗?
将对象管理器注入我的doesEntityExist()
函数的最佳做法是什么?
答案 0 :(得分:15)
最好的方法是在这里完全删除类中的静态方法。 ZF2使得通过名称获取服务变得非常容易,因此对于这样的用例,您不应该真正需要静态方法。
首先,清理您的服务:
namespace MyApp\Service;
use Doctrine\Common\Persistence\ObjectRepository;
use DoctrineModule\Validator\ObjectExists;
class ApiService
{
// ...
protected $validator;
public function __construct(ObjectRepository $objectRepository)
{
$this->validator = new \DoctrineModule\Validator\ObjectExists(array(
'object_repository' => $objectRepository,
'fields' => array('email')
));
}
public function exists($apiKey)
{
return $this->validator->isValid($apiKey);
}
// ...
}
现在为它定义一个工厂:
namespace MyApp\ServiceFactory;
use MyApp\Service\ApiService;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class ApiServiceFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$entityManager = $serviceLocator->get('Doctrine\ORM\EntityManager');
$repository = $entityManager->getRepository('Application\Entity\User');
return new ApiService($repository);
}
}
然后将服务名称映射到工厂(通常在您的模块中):
namespace MyApp;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return array(
'service_manager' => array(
'factories' => array(
'MyApp\Service\ApiService'
=> 'MyApp\ServiceFactory\ApiServiceFactory',
),
),
);
}
}
注意:您可能只想使用闭包而不是定义单独的工厂类,但是当您不使用该服务时,拥有工厂类可以提高性能。此外,在配置中使用闭包意味着您无法缓存合并配置,因此请考虑使用此处建议的方法。
这是一个没有工厂类的例子(再次考虑使用上面解释的方法):
namespace MyApp;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
class Module implements ServiceProviderInterface
{
public function getServiceConfig()
{
return array(
'factories' => array(
'MyApp\Service\ApiService' => function ($sl) {
$entityManager = $serviceLocator->get('Doctrine\ORM\EntityManager');
$repository = $entityManager->getRepository('Application\Entity\User');
return new MyApp\Service\ApiService($repository);
},
),
);
}
}
现在您可以在控制器中使用该服务:
class MyController extends AbstractActionController
{
// ...
public function apiAction()
{
$apiService = $this->getServiceLocator()->get('MyApp\Service\ApiService');
if ( ! $apiService->isValid($this->params('api-key')) {
throw new InvalidApiKeyException($this->params('api-key'));
}
// ...
}
// ...
}
您也可以在任何有服务经理的地方检索它:
$validator = $serviceLocator->get('MyApp\Service\ApiService');
作为补充建议,请考虑简化您的服务。由于isValid
已经是验证器的一种方法,因此您可以简单地返回验证器本身(为简单起见,使用闭包方法):
namespace MyApp;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use DoctrineModule\Validator\ObjectExists;
class Module implements ServiceProviderInterface
{
public function getServiceConfig()
{
return array(
'factories' => array(
'MyApp\Validator\ApiKeyValidator' => function ($sl) {
$entityManager = $serviceLocator->get('Doctrine\ORM\EntityManager');
$repository = $entityManager->getRepository('Application\Entity\User');
new ObjectExists(array(
'object_repository' => $objectRepository,
'fields' => array('email')
));
},
),
);
}
}
答案 1 :(得分:0)
就个人而言,我将服务作为'服务'并将其放入ServiceManager中。另外我会考虑重构代码。现在,您依赖于ObjectExists验证器,而后者依赖于实体存储库,这取决于实体管理器。在服务之外组合验证器并从工厂注入验证器要简单得多。这样,如果你需要使用不同的验证器,你只需要另外一个验证器。
class ApiService
{
protected $validator;
public function isValid($apiKey)
{
// other code
$isValid = $this->exists($apiKey);
}
public function exists($apiKey)
{
return $this->getValidator()->isValid($apiKey);
}
public function setValidator(\Zend\Validator\AbstractValidator $validator)
{
$this->validator = $validator;
return $this;
}
public function getValidator()
{
return $this->validator;
}
}
在Module.php中,将服务创建为工厂方法,或者更好地作为工厂类创建,但这仍然是您的练习:)
public function getServiceConfig()
{
return array(
'factories' => array(
'ApiService' => function($sm) {
$em = $sm->get('Doctrine\ORM\EntityManager');
$repo = $em->getRepository('Application\Entity\User');
$validator = new \DoctrineModule\Validator\ObjectExists($repo,
array('fields' => array('email')));
$service = new ApiService();
$service->setValidator($validator);
return $service;
},
),
);
}
现在,如果您需要一个不同的EntityManager,一个不同的Entity存储库,甚至是一个完整的不同验证器,您只需要更改上面几行,而不必深入研究您的服务代码。