2016-05-03 14 views
2

私は/experiment/{id}/...で始まるいくつかのルートを持っており、サインインしたユーザーの実験を取得するために同じロジックを書き直すことに飽き飽きしています。私は私のコードをリファクタリングできると思うが、私は@ParamConverterがより良い解決策になると推測している。Symfony @ParamConverterはユーザー関係を通じてエンティティを取得します

symfonyの@ParamConverter機能を利用するには、次のコードをどのように書き換えるのですか?私は自分のユーザーidとルートで実験idを使用してユーザーの実験で調印取得したい

class Experiment 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    */ 
    protected $id; 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="user_id", type="integer") 
    * @ORM\Id 
    */ 
    protected $userId; 

    /** 
    * @ORM\ManyToOne(targetEntity="UserBundle\Entity\User", inversedBy="experiments", cascade={"persist"}) 
    * @ORM\JoinColumn(name="user_id", referencedColumnName="id") 
    */ 
    protected $user; 

    // .. 

} 

次のように

/** 
* Displays details about an Experiment entity, including stats. 
* 
* @Route("/experiment/{id}/report", requirements={"id" = "\d+"}, name="experiment_report") 
* @Method("GET") 
* @Template() 
* @Security("has_role('ROLE_USER')") 
*/ 
public function reportAction(Request $request, $id) 
{ 
    $em = $this->getDoctrine()->getManager(); 

    $experiment = $em->getRepository('AppBundle:Experiment') 
     ->findOneBy(array(
      'id' => $id, 
      'user' => $this->getUser(), 
     )); 

    if (!$experiment) { 
     throw $this->createNotFoundException('Unable to find Experiment entity.'); 
    } 

    // ... 
} 

実験実体はcomposite primary keysを持っています。

+0

は、カスタムのparamコンバータは十分に、ちょうど注入 'security.token_storage'と'教義になります'をカスタムパラームコンバーターサービスの引数として使用します。 http://stfalcon.com/en/blog/post/symfony2-custom-paramconverter – malcolm

+0

多くのありがとう@malcolm私はjkucharovicの答えを受け入れました。これはあなたが何を示唆しているかを正確に示しています:) – mattvick

答えて

3

custom ParamConverterを使用してこれを達成できます。例えば、そのような何か:

namespace AppBundle\Request\ParamConverter; 

use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface; 
use Doctrine\ORM\EntityManager; 
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; 
use AppBundle\Entity\Experiment; 

class ExperimentConverter implements ParamConverterInterface 
{ 
    protected $em; 
    protected $user; 

    public function __construct(EntityManager $em, TokenStorage $tokenStorage) 
    { 
     $this->em = $em; 
     $this->user = $tokenStorage->getToken()->getUser(); 
    } 

    public function apply(Request $request, ParamConverter $configuration) 
    { 
     $object = $this->em->getRepository(Experiment::class)->findOneBy([ 
      'id' => $request->attributes->get('id'), 
      'user' => $this->user 
     ]); 

     if (null === $object) { 
      throw new NotFoundHttpException(
       sprintf('%s object not found.', $configuration->getClass()) 
      ); 
     } 

     $request->attributes->set($configuration->getName(), $object); 

     return true; 
    } 

    public function supports(ParamConverter $configuration) 
    { 
     return Experiment::class === $configuration->getClass(); 
    } 
} 

あなたのコンバータのサービスを登録し、それにタグを追加する必要があります。

# app/config/config.yml 
services: 
    experiment_converter: 
     class: AppBundle\Request\ParamConverter\ExperimentConverter 
     arguments: 
      - "@doctrine.orm.default_entity_manager" 
      - "@security.token_storage" 
     tags: 
      - { name: request.param_converter, priority: 1, converter: experiment_converter } 
+0

多くのありがとう@jkucharovicこれは素晴らしい作品です:)クラス名が常に正しい形式になっていることを確認するために、 'supports()'メソッドを少し変更しなければなりませんでした。私は私の変更を反映するためにあなたの答えを更新しました – mattvick

1

残念ながら、あなたが実際にURLのパラメータとして渡さない限り、現在ログインしているユーザーIDをparamコンバーターに挿入することはできません。

自分のコンバーターを作成することもできますが、実験をフェッチするための保護されたメソッドを作成するのが最善の方法だと思います。注釈として使用し、維持するために同じように簡単になります。

protected function getCurrentUsersExperiment($experimentId) 
{ 
    return $this->getDoctrine()->getManager()->getRepository('AppBundle:Experiment') 
     ->findOneBy(array(
      'id' => $experimentId, 
      'user' => $this->getUser() 
     )); 
} 

public function reportAction(Request $request, $id) 
{ 
    $experiment = $this->getCurrentUsersExperiment($id); 

    ... 
} 

それはsymfony best practicesに述べていますとおり:ParamFetcherいつでも適切なを使用しますが、それをoverthinkません。

関連する問題