Entity Manager in Service in Zend Framework 2

前端 未结 2 1426
孤城傲影
孤城傲影 2021-02-03 16:06

I have written a custom service for my module. This service provides public static functions which should validate a given token.

Now i want to implement another public

2条回答
  •  抹茶落季
    2021-02-03 16:58

    The best approach would be to completely remove the static methods from your class here. ZF2 makes it really easy to fetch services by their name, so you shouldn't really need static methods for such a use case.

    First of all, clean up your service:

    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);
        }
    
        // ...
    }
    

    Now define a factory for it:

    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);
        }
    }
    

    Then map the service name to the factory (usually in your module):

    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',
                    ),
                ),
            );
        }
    }
    

    NOTE: you may want to simply use a closure instead of defining a separate factory class, but having factory classes gives you a small performance boost when you're not using the service. Also, using a closure in configuration means you cannot cache the merged configuration, so consider using the method suggested here.

    Here's an example without the factory class (again, consider using the approach explained above):

    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);
                    },
                ),
            );
        }
    }
    

    Now you can use the service in your controllers:

    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'));
            }
    
            // ...
        }
    
        // ...
    }
    

    You can also retrieve it wherever you have the service manager:

    $validator = $serviceLocator->get('MyApp\Service\ApiService');
    

    As an additional suggestion, consider simplifying your service. Since isValid is already a method of your validator, you could simply return the validator itself (hereby using the closure method for simplicity):

    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')
                        )); 
                    },
                ),
            );
        }
    }
    

提交回复
热议问题