3

モジュール用のカスタム サービスを作成しました。このサービスは、特定のトークンを検証する public static 関数を提供します。

今、Doctrine-Entity が存在するかどうかをチェックする別の public static 関数を実装したいと考えています。この場合、サービスに object-manager または service-locator が必要です。

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')
        )); 
    }
}
  1. 関数を public static として実装し、それらを static メソッドとして呼び出すのは「ベストプラクティス」ですか?

  2. doesEntityExist()オブジェクトマネージャーを関数に挿入するベストプラクティスは何ですか?

4

2 に答える 2

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')
                    )); 
                },
            ),
        );
    }
}
于 2013-03-07T10:36:37.803 に答える
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、別のエンティティ リポジトリ、またはまったく別のバリデータが必要な場合でも、サービス コードを掘り下げる必要はなく、上記の数行を変更するだけで済みます。

于 2013-03-07T10:41:58.000 に答える