瀏覽代碼

Allow searching by tags, add downloads and favers to search API

Jordi Boggiano 12 年之前
父節點
當前提交
e91454935b

+ 1 - 1
src/Packagist/WebBundle/Controller/Controller.php

@@ -31,7 +31,7 @@ class Controller extends BaseController
             if (!$dlKeys) {
                 return $metadata;
             }
-            $res = $this->get('snc_redis.default')->mget(array_values($dlKeys));
+            $res = array_map('intval', $this->get('snc_redis.default')->mget(array_values($dlKeys)));
 
             $metadata = array(
                 'downloads' => array_combine(array_keys($dlKeys), $res),

+ 99 - 73
src/Packagist/WebBundle/Controller/WebController.php

@@ -187,96 +187,122 @@ class WebController extends Controller
         // transform q=search shortcut
         if ($req->query->has('q')) {
             $req->query->set('search_query', array('query' => $req->query->get('q')));
-        } elseif ($req->getRequestFormat() === 'json') {
-            return new JsonResponse(array('error' => 'Missing search query, example: ?q=example'), 400);
         }
 
-        if ($req->query->has('search_query')) {
+        $typeFilter = $req->query->get('type');
+        $tagsFilter = $req->query->get('tags');
+
+        if ($req->query->has('search_query') || $typeFilter || $tagsFilter) {
+            /** @var $solarium \Solarium_Client */
+            $solarium = $this->get('solarium.client');
+            $select = $solarium->createSelect();
+
+            // configure dismax
+            $dismax = $select->getDisMax();
+            $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2'));
+            $dismax->setPhraseFields(array('description'));
+            $dismax->setBoostFunctions(array('log(trendiness)^10'));
+            $dismax->setMinimumMatch(1);
+            $dismax->setQueryParser('edismax');
+
+            // filter by type
+            if ($typeFilter) {
+                $filterQueryTerm = sprintf('type:%s', $select->getHelper()->escapeTerm($typeFilter));
+                $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm);
+                $select->addFilterQuery($filterQuery);
+            }
+
+            // filter by tags
+            if ($tagsFilter) {
+                $tags = array();
+                foreach ((array) $tagsFilter as $tag) {
+                    $tags[] = $select->getHelper()->escapeTerm($tag);
+                }
+                $filterQueryTerm = sprintf('tags:(%s)', implode(' AND ', $tags));
+                $filterQuery = $select->createFilterQuery('tags')->setQuery($filterQueryTerm);
+                $select->addFilterQuery($filterQuery);
+            }
+
             $form->bind($req);
             if ($form->isValid()) {
-                /** @var $solarium \Solarium_Client */
-                $solarium = $this->get('solarium.client');
-
-                $select = $solarium->createSelect();
                 $escapedQuery = $select->getHelper()->escapeTerm($form->getData()->getQuery());
-                $typeFilter = $req->query->get('type');
+                $select->setQuery($escapedQuery);
+            }
+
+            $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select));
+            $paginator->setMaxPerPage(15);
+            $paginator->setCurrentPage($req->query->get('page', 1), false, true);
 
-                // filter by type
-                if ($typeFilter !== null) {
-                    $filterQueryTerm = sprintf('type:%s', $select->getHelper()->escapeTerm($typeFilter));
-                    $filterQuery = $select->createFilterQuery('type')->setQuery($filterQueryTerm);
-                    $select->addFilterQuery($filterQuery);
+            $metadata = $this->getPackagesMetadata($paginator);
+
+            if ($req->getRequestFormat() === 'json') {
+                try {
+                    $result = array(
+                        'results' => array(),
+                        'total' => $paginator->getNbResults(),
+                    );
+                } catch (\Solarium_Client_HttpException $e) {
+                    return new JsonResponse(array(
+                        'status' => 'error',
+                        'message' => 'Could not connect to the search server',
+                    ), 500);
                 }
-                $dismax = $select->getDisMax();
-                $dismax->setQueryFields(array('name^4', 'description', 'tags', 'text', 'text_ngram', 'name_split^2'));
-                $dismax->setPhraseFields(array('description'));
-                $dismax->setBoostFunctions(array('log(trendiness)^10'));
-                //this is very lenient, and may want to be refined
-                $dismax->setMinimumMatch(1);
-                $dismax->setQueryParser('edismax');
-                $select->setQuery($escapedQuery);
 
-                $paginator = new Pagerfanta(new SolariumAdapter($solarium, $select));
-                $paginator->setMaxPerPage(15);
-                $paginator->setCurrentPage($req->query->get('page', 1), false, true);
-
-                if ($req->getRequestFormat() === 'json') {
-                    try {
-                        $result = array(
-                            'results' => array(),
-                            'total' => $paginator->getNbResults(),
-                        );
-                    } catch (\Solarium_Client_HttpException $e) {
-                        return new JsonResponse(array(
-                            'status' => 'error',
-                            'message' => 'Could not connect to the search server',
-                        ), 500);
-                    }
+                foreach ($paginator as $package) {
+                    $url = $this->generateUrl('view_package', array('name' => $package->name), true);
 
-                    foreach ($paginator as $package) {
-                        $url = $this->generateUrl('view_package', array('name' => $package->name), true);
+                    $result['results'][] = array(
+                        'name' => $package->name,
+                        'description' => $package->description ?: '',
+                        'url' => $url,
+                        'downloads' => $metadata['downloads'][$package->id],
+                        'favers' => $metadata['favers'][$package->id],
+                    );
+                }
 
-                        $result['results'][] = array(
-                            'name' => $package->name,
-                            'description' => $package->description ?: '',
-                            'url' => $url
-                        );
+                if ($paginator->hasNextPage()) {
+                    $params = array(
+                        '_format' => 'json',
+                        'q' => $form->getData()->getQuery(),
+                        'page' => $paginator->getNextPage()
+                    );
+                    if ($tagsFilter) {
+                        $params['tags'] = (array) $tagsFilter;
                     }
-                    if ($paginator->hasNextPage()) {
-                        $result['next'] = $this->generateUrl('search', array(
-                            '_format' => 'json',
-                            'q' => $form->getData()->getQuery(),
-                            'page' => $paginator->getNextPage()
-                        ), true);
+                    if ($typeFilter) {
+                        $params['type'] = (array) $typeFilter;
                     }
-
-                    return new JsonResponse($result);
+                    $result['next'] = $this->generateUrl('search', $params, true);
                 }
 
-                if ($req->isXmlHttpRequest()) {
-                    try {
-                        return $this->render('PackagistWebBundle:Web:list.html.twig', array(
-                            'packages' => $paginator,
-                            'meta' => $this->getPackagesMetadata($paginator),
-                            'noLayout' => true,
-                        ));
-                    } catch (\Twig_Error_Runtime $e) {
-                        if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) {
-                            throw $e;
-                        }
-                        return new JsonResponse(array(
-                            'status' => 'error',
-                            'message' => 'Could not connect to the search server',
-                        ), 500);
+                return new JsonResponse($result);
+            }
+
+            if ($req->isXmlHttpRequest()) {
+                try {
+                    return $this->render('PackagistWebBundle:Web:list.html.twig', array(
+                        'packages' => $paginator,
+                        'meta' => $metadata,
+                        'noLayout' => true,
+                    ));
+                } catch (\Twig_Error_Runtime $e) {
+                    if (!$e->getPrevious() instanceof \Solarium_Client_HttpException) {
+                        throw $e;
                     }
+                    return new JsonResponse(array(
+                        'status' => 'error',
+                        'message' => 'Could not connect to the search server',
+                    ), 500);
                 }
-
-                return $this->render('PackagistWebBundle:Web:search.html.twig', array(
-                    'packages' => $paginator,
-                    'meta' => $this->getPackagesMetadata($paginator),
-                    'searchForm' => $form->createView(),
-                ));
             }
+
+            return $this->render('PackagistWebBundle:Web:search.html.twig', array(
+                'packages' => $paginator,
+                'meta' => $metadata,
+                'searchForm' => $form->createView(),
+            ));
+        } elseif ($req->getRequestFormat() === 'json') {
+            return new JsonResponse(array('error' => 'Missing search query, example: ?q=example'), 400);
         }
 
         return $this->render('PackagistWebBundle:Web:search.html.twig', array('searchForm' => $form->createView()));

+ 1 - 1
src/Packagist/WebBundle/Resources/views/Web/viewPackage.html.twig

@@ -44,7 +44,7 @@
             {% if version and version.tags|length %}
                 <p class="tags">
                     {%- for tag in version.tags -%}
-                        <a href="{{ url("allPackages", {tag: tag.name}) }}">{{ tag.name }}</a>
+                        <a href="{{ url("search", {tags: tag.name}) }}">{{ tag.name }}</a>
                     {%- endfor -%}
                 </p>
             {% endif %}