karakaram-blog

Symfony2のblogチュートリアルをリファクタリングしてみた(repositoryクラス)

 ツイート 0  シェア 0  Google+1 0  Hatena 1

symfony-logo

前回の記事では、blogチュートリアルを10章まで進め、Fixtureを導入してテストコードを書く準備を整えました。

今回は、11章まで写経した後に、私が独自に行ったリファクタリング内容を紹介します。アプリケーションはテストコードでガードされていますので、安心してリファクタリングを進めることができました。

リファクタリングでは下記の内容を試してみました。

  • GETリクエストとPOSTリクエストのアクションを分離
  • Repositoryクラスの導入
  • Repositoryクラスのテストコードを記述
  • Formクラスのテストコードを記述

長くなってしまったので、記事を2つに分けています。

動作確認環境

  • Symfony 2.0.11
  • PHP 5.3.10
  • PHPUnit 3.6.10

目次

  1. 11章のblogチュートリアルを終わらせる
  2. GETリクエストとPOSTリクエストのアクションを分離
  3. Repositoryクラス
  4. 次回はテストコード

11章のblogチュートリアルを終わらせる

11章のblogチュートリアルを終わらせます。

ソースコードは章ごとにタグを切ってgithubに置いてあります。
https://github.com/karakaram/symfony2-blog-tutorial/tags

GETリクエストとPOSTリクエストのアクションを分離

オリジナルのコードでは、コントローラ内でGETかPOSTかを判断して処理を分岐させていました。コントローラを短くするために、アクションを分けました。

newActionのみ抜粋して紹介します。

routing

# src/My/BlogBundle/Resources/config/routing.yml

blog_new:
    pattern:  /new
    defaults: { _controller: MyBlogBundle:Default:new }

blog_new_post:
    pattern:  /new
    defaults: { _controller: MyBlogBundle:Default:newPost }
    requirements:
        _method: POST

Controller

// src/My/BlogBundle/Controller/DefaultController.php

    public function newAction()
    {
        $form = $this->createForm(new PostType(), new Post());
        return $this->render('MyBlogBundle:Default:new.html.twig', array(
            'form' => $form->createView(),
        ));
    }

    public function newPostAction()
    {
        $form = $this->createForm(new PostType(), new Post());
        $form->bindRequest($this->getRequest());
        if (!$form->isValid()) {
            return $this->render('MyBlogBundle:Default:new.html.twig', array(
                'form' => $form->createView(),
			));
	    }
		//...
	}

Repositoryクラス

データベース関連のロジックをコントローラから分離してコントローラを短くするため、また、テストコードを書きやすくするためにRepositoryクラスを導入しました。

blogチュートリアルは複雑なデータベース関連の処理を行なっていませんので、コントローラはそれほど短くなりませんでした。

将来、関連するエンティティが増えてくるとRepositoryクラス導入のメリットが見えてくると思います。

DB更新系メソッドの戻り値は悩みましたが、テストを書きやすくするためにBooleanとしました。

Repositoryクラス

<?php
// src/My/BlogBundle/Repository/PostRepository.php

namespace My\BlogBundle\Repository;

use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
use My\BlogBundle\Entity\Post;

/**
 * PostRepository
 */
class PostRepository extends EntityRepository
{
    /**
     * search
     *
     * @return array Array of PostEntity
     */
    public function search()
    {
        $em = $this->getEntityManager();
        return $em->getRepository('MyBlogBundle:Post')->findAll();
    }

    /**
     * searchOneById
     *
     * @param Integer $id
     * @return \My\BlogBundle\Entity\Post
     * @throws \Doctrine\ORM\NoResultException
     */
    public function searchOneById($id)
    {
        $em = $this->getEntityManager();
        $post = $em->getRepository('MyBlogBundle:Post')->findOneById($id);
        if (empty($post)) {
            throw new NoResultException;
        }
        return $post;
    }

    /**
     * insert
     *
     * @param \My\BlogBundle\Entity\Post $post
     * @return Boolean
     */
    public function insert(Post $post)
    {
        $em = $this->getEntityManager('MyBlogBundle:Post');
        $em->persist($post);
        $em->flush();
        return true;
    }

    /**
     * delete
     *
     * @param Integer $id
     * @return Boolean
     * @throws \Doctrine\ORM\NoResultException
     */
    public function delete($id)
    {
        $em = $this->getEntityManager();
        $post = $this->searchOneById($id);
        $em->remove($post);
        $em->flush();
        return true;
    }

    /**
     * update
     *
     * @param \My\BlogBundle\Entity\Post $post
     * @param Integer $id
     * @return Boolean
     * @throws \Doctrine\ORM\NoResultException
     */
    public function update(Post $post)
    {
        $em = $this->getEntityManager();
        $this->searchOneById($post->getId());
        $em->flush();
        return true;
    }
}

コントローラ

Repositoryクラスの導入で、若干短くなりました。

<?php

namespace My\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use My\BlogBundle\Form\PostType;
use My\BlogBundle\Entity\Post;
use Doctrine\ORM\NoResultException;

class DefaultController extends Controller
{
    public function indexAction()
    {
        $em = $this->getDoctrine()->getEntityManager();
        $posts = $em->getRepository('MyBlogBundle:Post')->search();
        return $this->render('MyBlogBundle:Default:index.html.twig', array('posts' => $posts));
    }

    public function newAction()
    {
        $form = $this->createForm(new PostType(), new Post());
        return $this->render('MyBlogBundle:Default:new.html.twig', array(
            'form' => $form->createView(),
        ));
    }

	public function newPostAction()
    {
        $form = $this->createForm(new PostType(), new Post());
        $form->bindRequest($this->getRequest());
        if(!$form->isValid()) {
            return $this->render('MyBlogBundle:Default:new.html.twig', array(
                'form' => $form->createView()
            ));
        }
        $em = $this->getDoctrine()->getEntityManager();
        $em->getRepository('MyBlogBundle:Post')->insert($form->getData());
        $this->get('session')->setFlash('my_blog', '記事を追加しました');
        return $this->redirect($this->generateUrl('blog_index'));
    }

    public function showAction($id)
    {
        try {
            $em = $this->getDoctrine()->getEntityManager();
            $post = $em->getRepository('MyBlogBundle:Post')->searchOneById($id);
            return $this->render('MyBlogBundle:Default:show.html.twig', array('post' => $post));
        } catch (NoResultException $e) {
            throw new NotFoundHttpException('The post does not exist.');
        }
    }

    public function deleteAction($id)
    {
        try {
            $em = $this->getDoctrine()->getEntityManager();
            $em->getRepository('MyBlogBundle:Post')->delete($id);
            $this->get('session')->setFlash('my_blog', '記事を削除しました');
            return $this->redirect($this->generateUrl('blog_index'));
        } catch (NoResultException $e) {
            throw new NotFoundHttpException('The post does not exist.');
        }
    }

    public function editAction($id)
    {
        try {
            $em = $this->getDoctrine()->getEntityManager();
            $post = $em->getRepository('MyBlogBundle:Post')->searchOneById($id);
            $form = $this->createForm(new PostType(), $post);
            return $this->render('MyBlogBundle:Default:edit.html.twig', array(
                'post' => $post,
                'form' => $form->createView(),
            ));
        } catch (NoResultException $e) {
            throw new NotFoundHttpException('The post does not exist.');
        }
    }

    public function editPostAction($id)
    {
        try {
            $em = $this->getDoctrine()->getEntityManager();
            $post = $em->getRepository('MyBlogBundle:Post')->searchOneById($id);
            $form = $this->createForm(new PostType(), $post);
            $form->bindRequest($this->getRequest());
            if (!$form->isValid()) {
                return $this->render('MyBlogBundle:Default:edit.html.twig', array(
                    'post' => $post,
                    'form' => $form->createView(),
                ));
            }
            $post = $em->getRepository('MyBlogBundle:Post')->update($form->getData());
            $this->get('session')->setFlash('my_blog', '記事を編集しました');
            return $this->redirect($this->generateUrl('blog_index'));
        } catch (NoResultException $e) {
            throw new NotFoundHttpException('The post does not exist.');
        }
    }
}

次回はテストコード

次回の記事では、テストコードを中心に紹介します。

 ツイート 0  シェア 0  Google+1 0  Hatena 1