1

Zend Framework 2に基づいてApigility駆動のアプリケーションを開発しています。

現在、データベースで取得したデータをクライアントに直接送信しています。リクエストが来ると、MyResource#fetch(...)またはMyResource#fetchAll(...)がトリガーされ、MyServiceクラスで適切なメソッドが呼び出さMyMapperれ、 のようなメソッドでデータを取得するために呼び出されfindFooByBar(...)ます。

応答が送信される前に、データを処理したいと思います。どうやってやるの?


Apigility ZF HAL ドキュメントには、エンティティ データが取得されてからクライアントに送信されるまでの間にエンティティ データにアクセスする方法が示されています。さて、私はこれを試しました。それは醜く、そのようなタスクには多くのコードがあります。そして...うまくいきません。ただし、ここに私の試みを投稿したい:

namespace Portfolio;

...

class Module implements ApigilityProviderInterface {

    private $serviceManager;

    public function onBootstrap(MvcEvent $event) {
        $application = $event->getTarget();
        $this->serviceManager = $serviceManager = $application->getServiceManager();
        $viewHelperManager = $serviceManager->get('ViewHelperManager');
        $hal = $viewHelperManager->get('Hal');
        $hal->getEventManager()->attach('renderEntity', array($this, 'onRenderEntity'));
        $hal->getEventManager()->attach('renderCollection', array($this, 'onRenderCollection'));
    }

    public function onRenderEntity($event) {
        $entity = $event->getParam('entity');
        if ($entity->entity instanceof ProjectEntity) {
            $projectEntity = $entity->entity;
            $imageCollection = $this->tempCreateimagesForProject(
                $event, $entity->entity->getId()
            );
            $projectEntity->setImages($imageCollection);
            $event->setParam('entity', $projectEntity);
        }
    }

    public function onRenderCollection($event) {
        $collection = $event->getParam('collection');
        $projectCollection = $collection->getCollection();
        if ($projectCollection instanceof ProjectCollection) {
            foreach ($projectCollection as $key => $projectItem) {
                $tempProject = $projectCollection->getItem($key);
                $tempProject->append(
                    ['images' => $this->tempCreateimagesForProject($tempProject->offsetGet('id'))]
                );
                $projectCollection->getItem($key)->offsetSet($key, $tempProject);
            }
        }
    }

    private function tempCreateimagesForProject(Event $event, $projectId) {
        $imageService = $this->serviceManager->get('Portfolio\V2\Rest\ImageService');
        $imageCollection = $imageService->getImagesForProject($projectId);
        return $imageCollection;
    }

    ...

}
4

3 に答える 3

0

renderEntityrenderCollectionイベントを使用することは、この種のリソース固有のロジックを追加する正しい場所ではないと思います。より一般的な変更や付随的なカスタマイズに適しています。

このロジックをリソース リスナーに追加できます。したがって、クラスのfetchandfetchAllメソッドに、現在これらのandメソッドMyResourceに追加したカスタム コードを追加できます。onRenderEntityonRenderCollection

だから、このようなもの:

class MyResource extends AbstractResourceListener
{
    /**
     * Your image service dependency
     */
    protected $imageService;

    /* ... */

    public function fetch($id)
    {
        $project = $this->projectMapper->fetch($id);

        $imageCollection = $this->imageService->getImagesForProject($project);

        $project->setImages($imageCollection);
        return $project;
    }

    /* ... */

    public function fetchAll($params = array())
    {
        $projects = $this->projectMapper->fetchAll();

        foreach ($projects as $key => $project) {
            $imageCollection = $this->imageService->getImagesForProject($project);
            $project->setImages($imageCollection);
        }

        return $projects;
    }

    /* ... */
}
于 2015-03-07T14:48:47.890 に答える
0

考えられる解決策の 1 つは、Hydrator でデータを処理することです。そのため、カスタムの Hydrator クラスを作成し、ネストされたオブジェクトとリストを使用してアイテムを強化します。次のようになります。

Portfolio\V2\Rest\Project\ProjectHydrator

...

class ProjectHydrator extends ClassMethods {

    /**
     * @var ImageService
     */
    protected $imageService;

    ...

    /*
     * Doesn't need to be implemented:
     * the ClassMethods#hydrate(...) handle the $data already as wished.
     */
    /*
    public function hydrate(array $data, $object) {
        $object = parent::hydrate($data, $object);
        if ($object->getId() !== null) {
            $images = $this->imageService->getImagesForProject($object->getId());
            $object->setImages($images);
        }
        return $object;
    }
    */

    /**
     * @see \Zend\Stdlib\Hydrator\ClassMethods::extract()
     */
    public function extract($object) {
        $array = parent::extract($object);
        if ($array['id'] !== null) {
            $images = $this->imageService->getImagesForProject($array['id']);
            $array['images'] = $images;
        }
        return $array;
    }

}

モデル/データ取得ロジックの一部がハイドレーターに移動されるため、これは良い解決策ではありません。しかし、それは機能します。ここでは、このアプローチの実装を示します。ここでは、GitHub でのこのトピックに関するディスカッションを示します。

于 2015-03-31T14:11:13.370 に答える