重构“任氏有无轩”——第三天

Spread the love

今天继续加深书籍详细信息页面的构造。

在G+上95对我的进展发了一个评论:

再加上点自动抓取网上共享章节的功能

对这个要求,我只能说我只能实现一点点。我将在详细信息页面中构造一个显示豆瓣对应书籍的信息的部分。

另外,我要实现一个功能是在这个页面中编辑书籍tags的功能。

先看实现的界面:

detail

先讲在页面中编辑书籍tags。

这个其实很简单,在控制器中创建一个动作tagaddAction,用来处理“增加更多TAG”按钮的POST动作:

public function tagaddAction(Request $req)
{
    $q=$req->request->all();

    $q['newtags'];
    $id=$q['id'];

    $this->processTagAdd($tags, $id);
    $url=$this->get('router')->generate('book_detail', array('id'=>$id));

    return $this->redirect($url);
}

private function processTagAdd($tags, $id)
{
    $em=$this->getDoctrine()-gt;getEntityManager();
    $existing=$em->getRepository('trrsywxBundle:BookBook')->getTagsByBookId($id);
    $existing=$this->convertTagsToArray($existing);

    $book=$em->getRepository('trrsywxBundle:BookBook')->findOneBy(array('id'=>$id));

    $tags=trim($tags);
    $tagslist=  explode(' ', $tags);
    foreach ($tagslist as $tag)
    {
        if(!in_array($tag, $existing)) //This is a new tag
        {
            $booktaglist=new trrsywxBundleEntityBookTaglist();
            $booktaglist->setId($book);
            $booktaglist->setTag($tag);

            $em->persist($booktaglist);
        }
        $em->flush();
    }
}

这里有几个需要讲一讲的地方:

  • 在控制器中生成一个url,然后重定向。这也是一般表单post后所需要进行的最后一步。
  • 在processTagAdd中,需要注意$booktaglist->setId()的参数不是$book.id,而是$book本身。所以,虽然我传递进去的是$id,但是之前不得不用一个Repository函数来找出这本书。
  • 注意一个新的taglist是怎样创建,赋值,持续化的。最后,将所有持续化后的对象一次性flush到数据库中去。
  • 用in_array来判断要新加的tag是否已经存在于原来的taglist里,同时要将taglist对象中的tag提取出来变成一个数组——因为它本来是个对象数组。这个是由一个辅助函数convertTagsToArray完成的。

=====我是分割线=====

接下来讲一讲获得豆瓣的信息。

我用到了Snoopy这个库,关于如何在Symfony 2中加入第三方库的说明,参见这篇文章

获得豆瓣信息的核心代码如下:

private function getDoubanRemote($isbn)
{
        $bad_isbn = 'bad isbn';

        $url = "http://api.douban.com/book/subject/isbn/$isbn?alt=json";

        $s = new SnoopySnoopy();
        $s->agent = 'RSYWX.net - http://www.rsywx.net';
        $s->read_timeout = 1;
        //$s->user = 'taylor.ren@gmail.com';
        //$s->pass = 'xxxxxx';

        $s->fetch($url);
        $res = $s->results;
        if ($res == $bad_isbn) // My isbn is not found in douban
            return false;
        else
            return json_decode($res, true);
}

public function getDouban($isbn)
{
        $ret = $this->createDummyReturn();

        $res = $this->getDoubanRemote($isbn);
        if (!$res) // The above call not successful
        {
            return $ret;
        } else
        {
            if (array_key_exists('summary', $res))
                $summary = $res['summary']['$t'];
            else
                $summary = '(豆瓣还没有简介)';

            $ret['summary'] = $summary;
            $ret['alternate'] = $res['link'][1]['@href'];

            if (array_key_exists('db:tag', $res))
                $tags = $res['db:tag'];
            else
                $tags[] = '豆瓣没有给出任何TAG';

            $ret['tags'] = array(); //Clear up the dummy tag 'not found';
            foreach ($tags as $t)
            {
                $ret['tags'][] = $t['@name'];
            }

            $rating = $res['gd:rating']['@average'];
            if ($rating == 0)
                $rating = '(还没有评分)';
            $ret['rating'] = $rating;
        }
        return $ret;
}

其实没有什么技术含量,主要是从豆瓣API返回的数组中提取我用得着的数据而已。

到此,书籍详细页面已经完成。我接下来要做的是书籍列表部分。这个部分需要用到分页。可耻的是,Symfony 2没有内置分页部件,我需要自己来编写。这个会是一个挑战。

【本文收录于[go4pro.org]】

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.